2009-05-22 7 views
7

Estoy tratando de leer un archivo binario con la clase BinaryReader, y tengo que leerlo como bloques de UInt32, y luego hacer un poco de desplazamiento, etc. afterwords.¿Por qué BinaryReader.ReadUInt32() invierte el patrón de bits?

Pero, por alguna razón, el orden de los bits se invierte cuando uso el método ReadUInt32.

Si yo por ejemplo tengo un archivo en el que los primeros cuatro bytes es la siguiente con hexagonal, 0x12345678, que terminar así después de ser leído por ReadUInt32: 0x78563412.

Si utilizo los readBytes (4) método, me sale la matriz esperada:

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

¿Por qué es esto? ¿Es solo la forma en que .net representa uints en la memoria? ¿Es lo mismo en las diferentes plataformas (estoy ejecutando 64 bits en Windows 7, .net 3.5 sp1)?

+0

¿Puede calmar nuestra curiosidad diciéndonos cómo la solucionó? :) –

+1

Por supuesto :) En realidad no importa en qué dirección esté el orden de bytes, siempre que sea consistente en plataformas (x64, x86), aún puedo extraer los bits que necesito, solo tengo que cambiar mi bit cambiando. Por lo que puedo ver, uint está en general almacenado como little-endian, no solo la creación de uint por ReadUInt32, por lo que hace todo más fácil. –

Respuesta

8

Esto parece ser un problema endianness. The docs dice que ReadUint32 lee en little-endian, por lo que el primer byte es el menos significativo, por lo que va a la ubicación de memoria más baja. ¿Tu escritor debe ser un gran endian?

BinaryWriter.Write(UInt32)says it writes little-endian too. ¿Su fuente de datos binarios no es BinaryWriter?

Esencialmente lo que hay que hacer para solucionarlo es la siguiente:

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

Esto desplaza el byte menos significativo de hasta 24 bits, el segundo LSB hasta 8 bits, la tercera LSB abajo 8 bits, y el 4th LSB (el MSB) baja 24 bits. Hacer esto está cubierto en varias bibliotecas.

Tal vez usando BitConverter sería un poco más claro:

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í, esto tiene que ver con la forma en que el hardware de su computadora guarda recuerdos en la memoria. Puede ser diferente en diferentes plataformas, aunque la mayoría de las computadoras de escritorio deben ser iguales.

Esto se llama endianness - Wikipedia ver aquí:

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

1

Este es un problema de la plataforma Endianess. Cuando lees datos de una secuencia, debes leerlos de acuerdo con la endianess en la que se escribieron. Si creó los datos en .Net, entonces .Net lo leerá correctamente.

+0

lol 3 enlaces de wikipedia en menos de 1 minuto. ¡debería haber una insignia para eso! –

0

Leer Generic BinaryReader and BinaryWriter Extensions, una gran manera de manejar genérica fundición de la forma no administrado.

Para VB.NET (sólo el código de seguridad, también se puede lograr en C#) usa la siguiente:

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 

ahora se puede aplicar la misma funcionalidad para BitConverter, BinaryWriter etc.

Cuestiones relacionadas