8

我有可能包含或不包含 BOM的xml数据。byte[] byteArrayC# 中是否有任何标准方法可以从中删除 BOM?如果不是,那么处理所有情况(包括所有类型的编码)的最佳方法是什么?

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

我知道我可以找出60'<' 的 ASCII 值并在此之前忽略字节,但我不想这样做。

4

5 回答 5

10

所有 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();
}
于 2013-03-18T11:53:12.370 回答
2

您可以在从流中读取时执行类似这样的操作来跳过 BOM 字节。您需要扩展 Bom.cs 以包含更多编码,但是 afaik 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();
        }
    }
于 2013-05-01T09:43:53.957 回答
2

您不必担心 BOM。

如果由于某种原因您需要使用 XmlDocument 对象,则此代码可能对您有所帮助:

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

当我尝试使用 Google Api 从 gmail 帐户下载 xml 附件并且文件具有 BOM 并且使用 Encoding.UTF8.GetString(file_content) 无法“正常”工作时,它对我有用。

于 2019-02-17T01:52:44.880 回答
0

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

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

我不知道您的数组是如何使用的,也不知道您使用了哪些其他参数,所以我不能真正说出您将如何“删除”序列。您的选择似乎是:

  1. 如果您有startcount参数,您可以更改它们以反映数组的起点(在 BOM 之外)。
  2. 如果您只有一个count参数(数组的Length属性除外),您可以移动数组中的数据以覆盖 BOM,并进行count相应的调整。
  3. 如果您没有startcount参数,那么您需要创建一个新数组,其大小为旧数组减去 BOM 的大小,并将数据复制到新数组中。

要“删除”序列,您可能需要识别标记是否存在,然后将剩余的字节复制到新的字节数组中。或者,如果您维护字符数(数组的Length属性除外)

于 2013-03-18T13:13:38.213 回答
0

您还可以使用 StreamReader。

假设你有一个 MemoryStreamms

    using (StreamReader sr = new StreamReader(new MemoryStream(ms.ToArray()), Encoding.UTF8))
    {
         var bytesWithoutBOM = new UTF8Encoding(false).GetBytes(sr.ReadToEnd());
         var stringWithoutBOM = Convert.ToBase64String(bytesWithoutBOM );
    }
于 2021-06-16T12:55:21.433 回答