Почему BinaryReader.ReadUInt32 () изменить битовый шаблон?

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

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

Если у меня, например, есть файл, где первые четыре байта выглядят так в hex,0x12345678, они в конечном итоге, как это после того, как прочитал ReadUInt32: 0x78563412.

Если я использую метод ReadBytes(4), я получаю ожидаемый массив:

[0x00000000]    0x12    byte
[0x00000001]    0x34    byte
[0x00000002]    0x56    byte
[0x00000003]    0x78    byte

почему это? Это просто способ .net представляет uints в памяти? Это то же самое на разных платформах (я запускаю 64bit Windows 7, .net 3.5 sp1)?

6 ответов


Это, кажется,endianness вопрос. документы скажем, ReadUint32 читает в little-endian, поэтому первый байт наименее значим, поэтому он идет в самое низкое место памяти. Ваш писатель должен быть тупоконечников?

BinaryWriter.Write(UInt32) говорит, что он пишет младший разряд тоже. Ваш двоичный источник данных не BinaryWriter?

по сути то, что вам нужно сделать, чтобы исправить это:

uint a = 0x12345678;
uint b = ((a & 0x000000FF) << 24) + ((a & 0x0000FF00) << 8) + ((a & 0x00FF0000) >> 8) + ((a & 0xFF000000) >> 24);

это смещает наименее значительное байт до 24 бит, 2-й LSB до 8 бит, 3-й LSB вниз 8 бит, и 4-й LSB (MSB) вниз 24 бит. Это описано в нескольких библиотеках.

возможно, используя BitConverter было бы немного яснее:

uint a = 0x12345678;
byte[] bytes = BitConverter.GetBytes(a);
// Swap byte order
uint b = BitConverter.ToUInt32(new byte[] { bytes[3], bytes[2], bytes[1], bytes[0] }, 0);

Да, это связано с тем, как ваше компьютерное оборудование хранит uints в памяти. Он может отличаться на разных платформах, хотя большинство настольных компьютеров должны быть одинаковыми.

Это называется endianness -- смотрите Википедию здесь:

http://en.wikipedia.org/wiki/Endian


посмотрите в библиотеку MiscUtil Джона Скита для классов Endian*, таких как EndianBinaryReader и EndianBitConverter.

http://www.yoda.arachsys.com/csharp/miscutil/


Джон Скит написал BitConverter с настраиваемым endian-ness. Возможно, Вам это пригодится.

http://www.yoda.arachsys.com/csharp/miscutil/


Это вопрос платформы Endianess. Когда вы читаете данные из потока, вы должны прочитать их в соответствии с тем, как они были записаны. Если вы создали данные в .Net, то .Net будет читать их правильно.


читать общие расширения BinaryReader и BinaryWriter, отличный способ справиться с общим литьем неуправляемым способом.

для VB.NET (только безопасный код, также может быть достигнут в C#) используйте следующее:

Система Импорта.IO Система Импорта.Во время выполнения.CompilerServices Система Импорта.Во время выполнения.InteropServices

<HideModuleName()>
Public Module BinaryReaderExtensions

 <Extension()>
 Public Function Read(Of T As Structure)(br As BinaryReader) As T
  Dim bytes = br.ReadBytes(Marshal.SizeOf(GetType(T)))
  Dim handle = GCHandle.Alloc(bytes, GCHandleType.Pinned)
  Return Marshal.PtrToStructure(handle.AddrOfPinnedObject, GetType(T))
 End Function

 <Extension()>
 Public Function ReadReverse(Of T As Structure)(br As BinaryReader) As T
  Dim bytes = br.ReadBytes(Marshal.SizeOf(GetType(T))).Reverse.ToArray
  Dim handle = GCHandle.Alloc(bytes, GCHandleType.Pinned)
  Return Marshal.PtrToStructure(handle.AddrOfPinnedObject, GetType(T))
 End Function

End Module

Теперь вы можете реализовать ту же функциональность для BitConverter, for BinaryWriter etc.