2009-05-22 10 views
7

Ich versuche, eine binäre Datei mit der BinaryReader-Klasse zu lesen, und ich muss es als Blöcke von UInt32 lesen, und dann ein bisschen verschieben, usw. nachher.Warum kehrt BinaryReader.ReadUInt32() das Bitmuster um?

Aber aus irgendeinem Grund ist Bit Reihenfolge umgekehrt, wenn ich die ReadUInt32-Methode verwenden.

Wenn ich zum Beispiel eine Datei habe, in der die ersten vier Bytes in hex, 0x12345678, aussehen, enden sie so, nachdem sie von ReadUInt32 gelesen wurden: 0x78563412.

Wenn ich das Readbytes verwenden (4) Verfahren, erhalten ich die erwartete Array:

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

Warum ist das? Ist es nur die Art und Weise, wie .net die gespeicherten Daten darstellt? Ist es das gleiche über die verschiedenen Plattformen (ich 64bit Windows 7, .net 3.5 SP1 laufen)?

+0

Können Sie unsere Neugier unterdrücken, indem Sie uns sagen, wie Sie es behoben haben? :) –

+1

Natürlich :) In der Realität spielt es keine Rolle, wie die Byte-Reihenfolge ist, solange sie über platfroms (x64, x86) konsistent ist, kann ich immer noch die Bits extrahieren, die ich brauche, ich muss nur mein Bit ändern Verschiebung. Soweit ich sehen kann, wird uint im Allgemeinen als Little-Endian gespeichert, nicht nur als Uuit-Build von ReadUInt32, so dass alles einfacher wird. –

Antwort

8

Dies scheint ein endianness Thema. The docs sagt ReadUint32 liest Little-Endian so das erste Byte ist die niedrigste Bedeutung, so dass es an den niedrigsten Speicherort geht. Dein Schreiber muss Big-Endian sein?

BinaryWriter.Write(UInt32)says it writes auch little-endian. Ist Ihre binäre Datenquelle nicht BinaryWriter?

Wesentlichen, was Sie es zu beheben tun müssen, ist dies:

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

Damit verschiebt sich das am wenigsten signifikante Byte bis 24 Bit, das zweite LSB bis 8 Bits, die 3. LSB um 8 Bits, und die 4. LSB (das MSB) abwärts 24 Bits. Dies wird in mehreren Bibliotheken behandelt.

Vielleicht BitConverter mit wäre ein bisschen mehr klar sein:

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

Ja, dies hat damit zu tun, wie Ihre Computerhardware die Arbeitsspeicher speichert. Es kann auf verschiedenen Plattformen unterschiedlich sein, obwohl die meisten Desktop-Computer identisch sein sollten.

Dies wird Endian genannt - siehe wikipedia hier:

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

1

Dies ist eine Frage der Plattform Endianess. Wenn Sie Daten aus einem Stream lesen, müssen Sie sie entsprechend der Endianess lesen, in der sie geschrieben wurde. Wenn Sie die Daten in .Net erstellt haben, liest .Net sie korrekt.

+0

lol 3 wikipedia links in weniger als 1 minute. Dafür sollte es ein Abzeichen geben! –

0

lesen Generic BinaryReader and BinaryWriter Extensions, eine gute Möglichkeit, generisch zu behandeln, die nicht verwaltet Art und Weise zu werfen.

Für VB.NET verwenden Sie die folgende (sicheren Code nur, kann auch in C# erreicht werden):

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

Sie können nun implementieren die gleiche Funktionalität für , für BinaryWriter etc.