Какую кодировку использовать для чтения строки из файла?
Я анализирую файл (который я не генерирую), который содержит строку. Строка всегда предшествует 2 байта, которые говорят мне длину строки, которая следует.
Например:
05 00 53 70 6F 72 74
было бы:
Sport
Используя C# BinaryReader, я читаю строку, используя:
string s = new string(binaryReader.ReadChars(size));
Иногда есть странный характер, который, кажется, продвигает позицию потока дальше, чем следовало бы. Например:
0D 00 63 6F 6F 6B 20 E2 80 94 20 62 6F 6F 6B
Должно быть:
cook - book
и хотя он хорошо читается, поток заканчивается на два байта дальше, чем должен?! (Который тогда портит остальную часть анализа.)
Я предполагаю, что это как-то связано с 0xE2 посередине, но я не совсем уверен, почему или как с этим бороться.
Любые предложения с благодарностью!
3 ответа
Я предполагаю, что строка закодирована в UTF-8. 3-байтовая последовательность E2 80 94
соответствует одному символу Unicode U+2014 (EM DASH).
В вашем первом примере
05 00 53 70 6F 72 74
ни один из байтов не превышает 0x7F, и это является пределом для 7-битного ASCII. UTF-8 сохраняет совместимость с ASCII, используя 8-й бит, чтобы указать, что будет больше информации.
0D 00 63 6F 6F 6B 20 E2 80 94 20 62 6F 6F 6B
Тед заметил, что ваши "проблемы" начинаются с 0xE2, потому что это не 7-битный символ ASCII.
Первый байт 0x0D говорит нам, что должно быть 11 символов, но есть 13 байтов.
0xE2 говорит нам, что мы нашли начало последовательности UTF-8, так как установлен самый старший бит (больше 127). В этом случае последовательность, которая представляет - (EM Dash).
Как вы правильно сказали, проблема в символе E2. BinaryReader.ReadChars(n) не читает n-байтов, но n символов Unicode в кодировке UTF-8. Смотрите Википедию для кодировки Unicode. Термин, который вы используете, - это суррогатные персонажи. В UTF-8 символы в диапазоне от 000080 до 00009F представлены двумя байтами. Это причина вашего несоответствия смещения.
Вам нужно использовать BinaryReader.ReadBytes, чтобы исправить проблему смещения и передать ее в экземпляр Encoding.
Чтобы это работало, вам нужно прочитать байты с помощью BinaryReader, а затем декодировать его с правильной кодировкой. Предполагая, что вы имеете дело с UTF-8, вам нужно передать байтовый массив
Encoding.UTF8.GetString(byte [] rawData)
чтобы вернуть правильно закодированную строку.
С уважением, Алоис Краус