2015-05-13 4 views
2

Следующая проблема смутило меня много:Являются ли переменные (длинными, двойными ...) в файлах, хранящихся неправильно?

Я экспериментировал о том, как doubles и особенно их «специальные» ценности, как PositiveInfinity сохраняются в файле, который не было никаких проблем. Я сделал это в три простых шага: Создание double; записывая его в файл; чтение файла в файл byte. Это было довольно легко, и теперь я знаю, как Double.NaN выглядит в двоичном формате :)

Но потом я наткнулся на следующее:

Согласно .Net Framework-есть NegativeZero:

internal static double NegativeZero = BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000));

как это представляется довольно простой (по стандарту IEEE 754):

long представляет собой двоичный номер: 10000000 ...

Первый бит говорит, что double отрицательный. Итак, что представляет собой NegativeZero, является - 0 * 2^0, так как мантисса и показатель степени равны 0.

Представление «нормального» 0 будет тогда равным 64 битам, установленным на 0.


Но проблема читает эти цифры в byte массив. То, что я должен это следующий за NegativeZero: 12800 ... [двоичная: 100000 ...]

Но на самом деле это было не так наоборот: 00 ... 128! [binary: 00000 ... 0 10000000]

Моя первая мысль была: «Возможно, File.ReadAllBytes() возвращает все в неправильном порядке (что было бы неудобно)». Поэтому я решил проверить читателя с string (-> создать файл со строкой, прочитал его в byte массив)

Результат был просто отлично: «Привет» все еще «Hello» в byte массиве, а не в качестве примера из предложенного выше «olleH».


Опять Everthing в двух словах:

Запись двоичного числа (10000000 00000000 00000000) в файл работает отлично.

Чтение же двоичного числа в byte массив оказывается:

[0]00000000 [1]00000000 [2]10000000

Чтение файла не может быть проблемой, так как strings остаются теми же.

НО: Интерпретация массива byte обратно к исходной переменной (длинной, двойной ...) возвращает правильный результат.

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

Это правда? И если да, то почему это делается так, потому что, по моему мнению, это похоже на нарушение IEEE 754 (но, очевидно, работает)?

И, пожалуйста, поправьте меня, если я что-нибудь здесь отсутствует, как я до сих пор слишком смущен после нескольких часов поисков ответа на эту проблему ...

+5

Чтение http://en.wikipedia.org/wiki/Endianness может помочь вам. –

+0

@ Jon Skeet Спасибо! Но это помогло просто решить части проблемы. Остается вопрос: почему «строки» хранятся в правильном порядке? Можно ли испортить две системы в одном файле? Или это связано с кодированием строк? – Jibbow

+2

Endianness влияет только на определенные единицы измерения, такие как 'long' или' double'. Если вы хотите увидеть эффект endianness на строках, попробуйте использовать Encoding.Unicode vs 'Encoding.BigEndianUnicode'. –

ответ

2

Там нет универсального правила о том, что байты порядка должны быть в многобайтный структура.

Маленький обратный порядок байт подход поставил бы четыре-байтовое число 0x01020304 в байтах в порядке 0x04, 0x03, 0x02, 0x01.

Большой обратный порядок байт подход поставил бы тот же четыре-байтовое число в байтах в порядке 0x01, 0x02, 0x03, 0x04.

Ни один из них не является правильным из-за неправильного, хотя, очевидно, система, использующая один подход, нуждается в некотором преобразовании для взаимодействия с системой, использующей другую.

(Есть даже странные комбинации, как 0x03, 0x04, 0x01, 0x02 или 0x02, 0x01, 0x04, 0x03, но они гораздо реже, и обычно приходят примерно в связи с чем-то обрабатывать значения 4 байта в виде двух значений два байта с широкомасштабным подходом к упорядочению, а затем лечением тех, кто придерживается подхода малопринятого подхода, или наоборот).

Если вы работаете в .NET, вы, вероятно, используете чип Intel или один из них, совместимый с ним, и они используют little-endian порядок хранения значений в памяти. Копирование непосредственно из памяти в файл или обратно приведет к созданию файла little-endian.

Теперь строка представляет собой последовательность символов, а ее представление в памяти представляет собой последовательность байтов в некотором порядке. Таким образом, с «Hello» мы будем иметь какое-то представление H, а затем e, а затем l и так далее.

Это будет случай, является ли система малозначительной или big-endian.

Если, однако, представление одного из этих символов не является однобайтовым, то на это представление может влиять конечная точка.

Наиболее распространенным современным представлением для использования файла (и действительно единственным, использующим 99% времени) является UTF-8. UTF-8 будет определять многобайтовые последовательности для символов с кодовой точкой выше U + 007F, но порядок этой последовательности определяется самим UTF-8 и поэтому не зависит от сущности.

Второе наиболее распространенное современное представление (и одно из оставшихся 1% времени, если у вас есть веские причины) - это UTF-16. UTF-16 имеет дело с символами как 16-битные единицы или как два 16-битных блока для символов выше U + FFFF. В случае использования двух 16-разрядных блоков порядок этих единиц указывается в самом UTF-16. Тем не менее, порядок двух октетов, представляющих эти 16-битовые единицы, не указан на этом уровне и, следовательно, зависит от сущности.

Следовательно, UTF-16 может быть представлен в байтах как UTF-16LE или UTF-16BE, так и как один или другой с байтом-порядком в начале файла, чтобы позволить программе чтения определить, что используется , Таким образом, с UTF-16 "привет" может быть:

0x00 0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F 

или это может быть:

0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F 0x00 

 Смежные вопросы

  • Нет связанных вопросов^_^