1

使用 .net ASCIIEncoding 类将字节数组解码为字符串时,我是否需要编写一些代码来检测和删除字节顺序标记,或者是否可以告诉 ASCIIEncoding 不将字节顺序标记解码为字符串?

这是我的问题,当我这样做时:

string someString = System.Text.ASCIIEncoding.Default.GetString(someByteArray)

someString 看起来像这样:

<?xml version="1.0"?>.......

然后当我打电话给这个时:

XElement.Parse(someString)

由于前三个字节而引发异常: EF BB BF - UTF8 字节顺序标记。所以我想如果我指定UTF8编码,而不是默认,像这样:

System.Text.ASCIIEncoding.UTF8.GetString(someByteArray)

ASCIIEncoding 不会尝试将字节顺序标记解码为字符串。当我将返回的字符串复制到 notepad++ 中时,我可以看到一个 ? XML 标记前面的字符。所以现在字节顺序标记被解码为一个垃圾字符。在这种情况下,停止字节顺序标记被解码的最佳方法是什么?

4

3 回答 3

5

请不要使用

ASCIIEncoding.UTF8

这真的只是

Encoding.UTF8

它根本不使用ASCIIEncoding。它只是在您的源代码中看起来像它。

从根本上说,问题在于您的文件UTF-8,而不是ASCII。这就是为什么它有一个 UTF-8 字节顺序标记。我强烈建议您使用 Encoding.UTF8一种或另一种方式来读取 UTF-8 文件。

如果您使用 读取文件File.ReadAllText,我怀疑它会自动删除 BOM。或者您可以在调用XElement.Parse. 使用错误的编码(ASCII 或 Encoding.Default)不是正确的方法。同样,它不是垃圾字符。这是一个非常有用的字符,非常强烈地表明它确实一个 UTF-8 文件——只是你不希望它在这个特定的上下文中。“垃圾”给人的印象是它是不应该出现在文件中的损坏数据,而且绝对不是这种情况。

另一种方法是完全避免将其转换为文本。例如:

XElement element;
using (XmlReader reader = XmlReader.Create(new MemoryStream(bytes))
{
    element = XElement.Load(reader);
}

这样编码将被自动检测。

于 2011-02-23T23:49:47.443 回答
2

System.Text.Encoding.GetString()保留 BOM(如果存在)并将其转换为 UTF-16 BOM (U+FEFF)。认为这是一个功能。严格来说,这是正确的做法,因为扔 BOM 会使转换有损且不可往返。不过,有点令人惊讶的是,他们没有提供一个标志来让你指定所需的行为,但你就在那里。所以......你有两个选择:

  1. 转换为字符串,查找 BOM 并在调用字符串之前将其删除XElement.Parse()。或者...

  2. 包装byte[]in a MemoryStreamMemoryStreamin aStreamReader并使用XElement.Load()来进行解析。

你的选择。这是一些可以工作的示例代码:

using System.IO;
using System.Text;
using System.Xml.Linq;

namespace TestDrive
{
    class Program
    {
        public static void Main()
        {
            byte[] octets = File.ReadAllBytes( "utf8-encoded-document-with-BOM.xml" ) ;

            // -----------------------------------------------
            // option 1: use a memory stream and stream reader
            // -----------------------------------------------
            using ( MemoryStream ms = new MemoryStream( octets) )
            using ( StreamReader sr = new StreamReader( ms , Encoding.UTF8 , true )   )
            {
                XElement element1 = XElement.Load( sr ) ;
            }

            // --------------------------------------------------------------------
            // option 2: convert to string, then look for and remove BOM if present
            // 
            // The .Net framework Encoding.GetString() methods preserve the BOM if
            // it is present. Since the internal format of .Net string is UTF-16,
            // the BOM is converted to the UTF-16 encoding (U+FEFF).
            // 
            // Consider this a feature.
            // --------------------------------------------------------------------
            // convert to UTF-16 string
            string       xml       = Encoding.UTF8.GetString( octets ) ;
            // Two different ways of getting the BOM
            //string UTF16_BOM = Encoding.Unicode.GetString(Encoding.Unicode.GetPreamble()).ToCharArray() ;
            const string UTF16_BOM = "\uFEFF" ; 
            // parse the element, removing the BOM if we see it.
            XElement element2 = XElement.Parse( xml.StartsWith( UTF16_BOM ) ? xml.Substring(1) : xml ) ;

            return ;
        }
    }
}
于 2011-02-24T00:58:07.147 回答
1

这不是一个答案,但评论中的代码很糟糕,把它放在你的问题中感觉有点粗鲁。你真的想这样做吗:

Byte[] bytes = new byte [] { 0xEF,0xBB,0xBF, 0x57, 0x44 };
String txt = Encoding.UTF8.GetString(bytes);
Console.WriteLine("String length {0}", txt.Length);
Console.WriteLine("String '{0}'", txt);
Console.WriteLine("Chars '{0}'", String.Join(",", txt.Select(chr => ((int)chr).ToString("x2"))));

想知道为什么你会得到:

String length 3
String 'WD'
String 'feff,57,44'

我当然是...

于 2011-02-24T00:00:03.343 回答