2009-05-22 13 views
7

Sto provando a leggere un file binario con la classe BinaryReader, e ho bisogno di leggerlo come blocchi di UInt32, e poi fare un po 'di shifting afterc.Perché BinaryReader.ReadUInt32() inverte il pattern di bit?

Ma, per qualche motivo, l'ordine dei bit è invertito quando utilizzo il metodo ReadUInt32.

Se io per esempio ho un file in cui i primi quattro byte sembra che questo in esadecimale, 0x12345678, finiscono in questo modo dopo essere stato letto da ReadUInt32: 0x78563412.

se uso il metodo readBytes (4), ottengo l'array atteso:

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

Perché è questo? È solo il modo in cui .net rappresenta gli ui in memoria? È lo stesso tra le diverse piattaforme (sto utilizzando Windows 7 a 64 bit, .net 3.5 sp1)?

+0

Riesci a sedare la nostra curiosità dicendoci come lo hai risolto? :) –

+1

Ovviamente :) In realtà non importa quale sia l'ordine dei byte, purché sia ​​coerente su platfroms (x64, x86), posso ancora estrarre i bit che mi servono, devo solo cambiare il mio bit mutevole. Per quanto posso vedere, uint è generalmente memorizzato come little-endian, non solo la build uint di ReadUInt32, quindi rende tutto più semplice. –

risposta

8

questo sembra essere un problema endianness. The docs dire ReadUint32 legge in little-endian quindi il primo byte è il meno significativo in modo che passi alla posizione di memoria più bassa. Il tuo scrittore deve essere big-endian?

BinaryWriter.Write(UInt32)says it writes little-endian anche. La tua fonte di dati binari non è BinaryWriter?

Essenzialmente quello che devi fare per risolvere il problema è questo:

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

Questo sposta il byte meno significativo up 24 bit, il secondo LSB fino 8 bit, il 3 ° LSB giù 8 bit, e la 4 ° LSB (il MSB) in calo di 24 bit. Fare questo è coperto da diverse librerie.

Forse usando BitConverter sarebbe un po 'più chiaro:

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

Sì, questo ha a che fare con il modo in cui l'hardware del computer memorizza i suggerimenti in memoria. Può essere diverso su piattaforme diverse, anche se la maggior parte dei computer desktop dovrebbe essere la stessa.

Questo è chiamato endianness - vedi Wikipedia qui:

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

1

questo è un problema di piattaforma di Endianess. Quando leggi i dati da uno stream devi leggerlo di conseguenza con l'endianess che è stato scritto come. Se hai creato i dati in .Net, allora .Net lo leggerà correttamente.

+0

lol 3 collegamenti wikipedia in meno di 1 minuto. ci dovrebbe essere un distintivo per questo! –

0

Generic BinaryReader and BinaryWriter Extensions Leggi, un ottimo modo per gestire generico gettando la strada non gestito.

Per VB.NET (solo il codice di sicurezza, può essere ottenuta anche in C#) utilizzare il seguente:

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

È ora possibile implementare la stessa funzionalità per BitConverter, per BinaryWriter ecc.

Problemi correlati