2009-05-22 16 views
7

J'essaie de lire un fichier binaire avec la classe BinaryReader, et j'ai besoin de le lire en blocs de UInt32, puis de faire un peu de décalage, etc. afterwords. Mais, pour une raison quelconque, l'ordre des bits est inversé lorsque j'utilise la méthode ReadUInt32. Si je ai par exemple un fichier où les quatre premiers octets ressemble à ceci en hexadécimal, 0x12345678, ils finissent comme ça après avoir été lus par ReadUInt32: 0x78563412.Pourquoi BinaryReader.ReadUInt32() inverse le modèle binaire?

Si j'utilise la méthode readBytes (4), je reçois le tableau attendu:

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

Pourquoi est-ce? Est-ce juste la façon .net représente des uints en mémoire? Est-ce la même chose sur les différentes plates-formes (je cours 64 bits Windows 7, .net 3.5 SP1)?

+0

Pouvez-vous étonner notre curiosité en nous disant comment vous l'avez fixé? :) –

+1

Bien sûr :) En réalité, peu importe la façon dont l'ordre des octets est, tant qu'il est cohérent sur les platfroms (x64, x86), je peux toujours extraire les bits dont j'ai besoin, je dois juste changer mon bit déplacement. Pour autant que je puisse le voir, uint est généralement stocké comme little-endian, et pas seulement comme uint construit par ReadUInt32, ce qui rend tout plus facile. –

Répondre

8

Cela semble être un problème endianness. The docs dit ReadUint32 lit en little-endian donc le premier octet est le moins significatif donc il va à l'emplacement mémoire le plus bas. Votre écrivain doit être big-endian?

BinaryWriter.Write(UInt32)says it writes petit-boutiste aussi. Est-ce que votre source de données binaires n'est pas BinaryWriter?

Essentiellement ce que vous devez faire pour y remédier est la suivante:

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

Cela déplace l'octet moins significatif jusqu'à 24 bits, le 2 LSB jusqu'à 8 bits, le 3 LSB vers le bas 8 bits, et 4ème LSB (le MSB) en baisse de 24 bits. Faire cela est couvert dans plusieurs bibliothèques.

Peut-être en utilisant BitConverter serait un peu plus clair:

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

Oui, cela a à voir avec la façon dont votre matériel informatique stocke les informations en mémoire. Il peut être différent sur différentes plates-formes, bien que la plupart des ordinateurs de bureau soient identiques.

Ceci est appelé boutisme - voir wikipedia ici:

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

1

Ce numéro de la plate-forme Endianess. Lorsque vous lisez des données d'un flux, vous devez le lire en conséquence à l'endianess il a été écrit. Si vous avez créé les données dans .Net, alors .Net le lira correctement.

+0

lol 3 liens wikipedia en moins de 1 minute. il devrait y avoir un badge pour ça! –

0

Lire Generic BinaryReader and BinaryWriter Extensions, une excellente façon de gérer générique la coulée de la façon non géré.

Pour VB.NET (code sûr que, peut également être réalisé en C#) utiliser les éléments suivants:

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

Vous pouvez maintenant mettre en œuvre la même fonctionnalité pour BitConverter, pour BinaryWriter etc.