Как сказать классу ASCIIEncoding не декодировать метку порядка байтов - PullRequest
1 голос
/ 24 февраля 2011

При декодировании байтового массива в строку с использованием класса .net ASCIIEncoding мне нужно написать некоторый код для обнаружения и удаления метки порядка байтов, или можно сказать ASCIIEncoding не декодировать метку порядка байтов в строку?

Вот моя проблема, когда я делаю это:

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

someString будет выглядеть так:

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

Тогда, когда я вызываю это:

XElement.Parse(someString)

исключение выдается из-за первых трех байтов: EF BB BF - метка порядка байтов UTF8.Поэтому я подумал, что если я укажу кодировку UTF8, а не Default, как это:

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

ASCIIEncoding не будет пытаться декодировать метку порядка байтов в строку.Когда я копирую возвращенную строку в notepad ++, я вижу?символ перед тегом XML.Так что теперь метка порядка байтов декодируется в один символ мусора.Как лучше всего остановить декодирование метки порядка байтов в этом случае?

Ответы [ 3 ]

5 голосов
/ 24 февраля 2011

Пожалуйста, не используйте

ASCIIEncoding.UTF8

Это действительно просто

Encoding.UTF8

Он вообще не использует ASCIIEncoding.Это просто выглядит в вашем исходном коде.

По сути, проблема в том, что ваш файл это UTF-8, это , а не ASCII.Вот почему он имеет метку порядка байтов UTF-8.Я настоятельно рекомендую вам использовать Encoding.UTF8 для чтения файла UTF-8, тем или иным способом.

Если вы читаете файл с File.ReadAllText, я подозреваю, что он будетудалить спецификацию автоматически.Или вы можете просто обрезать его потом, прежде чем позвонить XElement.Parse.Использование неправильной кодировки (ASCII или Encoding.Default) не правильный подход.Точно так же это , а не мусорный персонаж.Это очень полезный символ, дающий очень четкое указание на то, что на самом деле является файлом UTF-8 - просто вы не хотите его в данном конкретном контексте .«Мусор» создает впечатление, что это поврежденные данные, которые не должны присутствовать в файле, и это определенно не тот случай.

Другой подход - вообще не использовать его для преобразования в текст.Например:

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

Таким образом, кодировка будет определяться автоматически.

2 голосов
/ 24 февраля 2011

System.Text.Encoding.GetString() сохраняет спецификацию, если она присутствует, и преобразует ее в спецификацию UTF-16 (U + FEFF). Считайте, что это особенность. Строго говоря, это правильная вещь, потому что бросание спецификации сделало бы конверсию потерянной и не допускающей циклического отключения. Удивительно, однако, что они не предоставили флаг, позволяющий вам указать желаемое поведение, но вы здесь. Итак ... у вас есть два варианта:

  1. Преобразовать в строку, найти спецификацию и удалить ее до вызова XElement.Parse() в строке. Или ...

  2. оберните byte[] в MemoryStream, MemoryStream в StreamReader и используйте 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 ;
        }
    }
}
1 голос
/ 24 февраля 2011

Это не ответ, но код в комментариях ужасен, и было немного грубо вставить это в ваш вопрос.Вы действительно пытаетесь сделать это:

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'

Я, конечно, ...

...