如何从字节数组中删除BOM

本文关键字:删除 BOM 数组 字节数 字节 | 更新日期: 2023-09-27 18:04:22

我在byte[] byteArray中有xml数据,可能包含也可能不包含BOM。在c#中有什么标准的方法来删除BOM吗?如果不是,最好的方法是什么,它处理所有的情况,包括所有类型的编码,做同样的?

实际上,我正在修复代码中的一个错误,我不想更改太多代码。所以如果有人能给我代码来删除BOM就更好了。

我知道我可以找到60它是'<'的ASCII值并忽略之前的字节但我不想这样做

如何从字节数组中删除BOM

所有c# XML解析器都会自动为您处理BOM。我推荐使用XDocument——在我看来,它提供了最清晰的XML数据抽象。

以XDocument为例:

using (var stream = new memoryStream(bytes))
{
  var document = XDocument.Load(stream);
  ...
}

一旦你有了一个XDocument,你就可以用它来省略没有BOM的字节:

using (var stream = new MemoryStream())
using (var writer = XmlWriter.Create(stream))
{
  writer.Settings.Encoding = new UTF8Encoding(false);
  document.WriteTo(writer);
  var bytesWithoutBOM = stream.ToArray();
}

您不必担心BOM。

如果出于某种原因你需要使用XmlDocument对象,也许这段代码可以帮助你:

byte[] file_content = {wherever you get it};
XmlDocument xml = new XmlDocument();
xml.Load(new MemoryStream(file_content));

它为我工作时,我试图下载xml附件从gmail帐户使用谷歌Api和文件有BOM和使用Encoding.UTF8.GetString(file_content)没有工作"正常"。

您可以这样做,以便在从流读取时跳过BOM字节。您需要扩展BOM. cs以包含更多的编码,但是恐怕UTF是使用BOM的唯一编码…但我很可能错了。

我从这里得到了编码类型的信息

using (var stream = File.OpenRead("path_to_file"))
{
    stream.Position = Bom.GetCursor(stream);
}

public static class Bom
{
        public static int GetCursor(Stream stream)
        {
            // UTF-32, big-endian
            if (IsMatch(stream, new byte[] {0x00, 0x00, 0xFE, 0xFF}))
                return 4;
            // UTF-32, little-endian
            if (IsMatch(stream, new byte[] { 0xFF, 0xFE, 0x00, 0x00 }))
                return 4;
            // UTF-16, big-endian
            if (IsMatch(stream, new byte[] { 0xFE, 0xFF }))
                return 2;
            // UTF-16, little-endian
            if (IsMatch(stream, new byte[] { 0xFF, 0xFE }))
                return 2;
            // UTF-8
            if (IsMatch(stream, new byte[] { 0xEF, 0xBB, 0xBF }))
                return 3;
            return 0;
        }
        private static bool IsMatch(Stream stream, byte[] match)
        {
            stream.Position = 0;
            var buffer = new byte[match.Length];
            stream.Read(buffer, 0, buffer.Length);
            return !buffer.Where((t, i) => t != match[i]).Any();
        }
    }

你也可以使用StreamReader。

假设你有一个内存流ms

    using (StreamReader sr = new StreamReader(new MemoryStream(ms.ToArray()), Encoding.UTF8))
    {
         var bytesWithoutBOM = new UTF8Encoding(false).GetBytes(sr.ReadToEnd());
         var stringWithoutBOM = Convert.ToBase64String(bytesWithoutBOM );
    }

您必须在字节数组的开始处识别字节顺序标记。有几种不同的组合,如http://www.unicode.org/faq/utf_bom.html#bom1所述。

创建一个小状态机,从字节数组的开头开始查找这些序列。

我不知道你的数组是如何使用的,也不知道你使用的其他参数是什么,所以我不能真正说你是如何"删除"序列的。您的选项似乎是:

  1. 如果你有startcount参数,你可以改变那些反映数组的起点(超出BOM)。
  2. 如果你只有一个count参数(而不是数组的Length属性),你可以移动数组中的数据来覆盖BOM,并相应地调整count
  3. 如果你没有startcount参数,那么你需要创建一个新的数组,这是旧数组减去BOM的大小,并复制数据到新的数组。

要"删除"序列,您可能需要识别标记,如果它在那里,然后将剩余的字节复制到一个新的字节数组。或者,如果您维护一个字符计数(除了数组的Length属性)