Perché BinaryReader.ReadUInt32 () invertire la sequenza di bit?
-
23-08-2019 - |
Domanda
Sto cercando di leggere un file binario con la classe BinaryReader, e ho bisogno di leggerlo come blocchi di UInt32, e poi fare un po 'po' di spostamento ecc afterwords.
Ma, per qualche ragione ordine dei bit è invertito quando uso 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? E 'solo il modo in cui .NET rappresenta uints in memoria? E 'lo stesso tra le diverse piattaforme (io sono in esecuzione a 64 bit di Windows 7, .net 3.5 SP1)?
Soluzione
Questo sembra essere un endianness problema. La documentazione dicono ReadUint32 legge in little-endian in modo che il primo byte è il meno significativo così si va alla locazione di memoria più basso. Il tuo scrittore deve essere big-endian?
BinaryWriter.Write(UInt32) href="http://msdn.microsoft.com/en-us/library/d79ecdwh.aspx" rel="noreferrer"> dice che scrive little-endian troppo. È la vostra fonte di dati binari non BinaryWriter?
In sostanza ciò che è necessario 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 2 ° LSB fino 8 bit, il 3 ° LSB giù 8 bit, e il 4 ° LSB (MSB) verso il basso 24 bit. Fare questo è coperto in 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);
Altri suggerimenti
Sì, questo ha a che fare con come il vostro computer Ferramenta uints in memoria. Può essere diverso su diverse piattaforme, anche se la maggior parte dei computer desktop dovrebbe essere lo stesso.
Questo è chiamato endianness - vedi wikipedia qui:
Se vuoi in biblioteca MiscUtil Jon Skeet per le classi Endian *, come EndianBinaryReader e EndianBitConverter.
di Jon Skeet scritto un BitConverter con configurabile endian-ness. Si potrebbe trovare utile.
Questo è un problema di endianess . Quando si leggono i dati da un flusso è necessario leggere di conseguenza alla endianess è stato scritto come. Se è stato creato i dati in .Net, quindi Net leggerà correttamente.
Generico BinaryReader e BinaryWriter estensioni , un ottimo modo per gestire generici gettando il modo in cui non gestito.
Per VB.NET (codice sicuro solo, può essere ottenuta anche in C #) utilizzare il seguente:
Imports System.IO Importazioni System.Runtime.CompilerServices Le importazioni 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
A questo punto è possibile implementare la stessa funzionalità per BitConverter
, per BinaryWriter
etc.