2009-05-22 9 views
7

Próbuję odczytać plik binarny za pomocą klasy BinaryReader, a ja potrzebuję go odczytać jako bloki UInt32, a następnie trochę przesunąć itd.Dlaczego BinaryReader.ReadUInt32() odwraca wzór bitowy?

Jednak z jakiegoś powodu kolejność bitów jest odwracana, gdy używam metody ReadUInt32.

Jeśli na przykład masz plik gdzie pierwsze cztery bajty wygląda to w hex, 0x12345678, kończy się tak po odczytywane przez ReadUInt32: 0x78563412.

Jeśli używam ReadBytes metoda (4), pojawia się oczekiwany tablicy:

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

dlaczego tak jest? Czy to po prostu sposób .net reprezentuje uints w pamięci? Czy jest tak samo na różnych platformach (mam 64-bitowy system Windows 7, .net 3.5 sp1)?

+0

Czy możesz stłumić naszą ciekawość, mówiąc nam, jak to naprawiłeś? :) –

+1

Oczywiście :) W rzeczywistości nie ma znaczenia, w jaki sposób kolejność bajtów jest tak długa, jak długo jest spójna na platfromach (x64, x86), wciąż mogę wydobyć potrzebne fragmenty, po prostu muszę zmienić mój bit przeniesienie. O ile widzę, uint jest ogólnie przechowywany jako little-endian, a nie tylko uint build ReadUInt32, dzięki czemu wszystko jest łatwiejsze. –

Odpowiedz

8

To wydaje się być endianness problem. The docs powiedzieć ReadUint32 czyta w little-endian, więc pierwszy bajt jest najmniej znaczący, więc idzie do najniższej lokalizacji pamięci. Twój pisarz musi być big-endianinem?

BinaryWriter.Write(UInt32)says it writes mało-endian też. Czy Twoje źródło danych binarnych nie jest BinaryWriter?

Zasadniczo to, co trzeba zrobić, aby to naprawić to:

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

ten przesuwa najmniej znaczący bajt o 24 bitów, 2. LSB o 8 bitów, 3. LSB dół 8 bitów, i tym 4. LSB (MSB) w dół 24 bity. Robi się to w kilku bibliotekach.

Może użyciu BitConverter byłby nieco bardziej jasne:

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); 
8

Tak, ma to związek z tym, jak sprzęt komputerowy przechowuje zapisy w pamięci. Może być różny na różnych platformach, chociaż większość komputerów stacjonarnych powinna być taka sama.

ten nazywany jest kolejność bajtów - patrz wikipedia tutaj:

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

1

Jest to kwestia platformy Endianess. Kiedy czytasz dane ze strumienia, musisz je przeczytać zgodnie z tym, na co go zapisałeś. Jeśli utworzyłeś dane w .Net, to .NET odczyta je poprawnie.

+0

lol 3 linki wikipedia w mniej niż 1 minutę. na tym powinna być odznaka! –

0

Czytaj Generic BinaryReader and BinaryWriter Extensions, to świetny sposób, aby obsługiwać rodzajowy odlewania niezarządzanej sposób.

Dla VB.NET (tylko bezpieczny kod, można również osiągnąć w C#) użyć następujących:

Imports System.IO Importuje System.Runtime.CompilerServices Importuje System.Runtime.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 

Teraz można zaimplementować ta sama funkcja dla BitConverter, dla BinaryWriter itd.