2009-05-22 116 views
7

我想用BinaryReader类读取二进制文件,并且需要将它作为UInt32块读取,然后做一些位移等后缀。为什么BinaryReader.ReadUInt32()会颠倒位模式?

但是,由于某种原因,当我使用ReadUInt32方法时,位顺序反转。

如果我比如有一个文件,其中前四个字节看起来像这样十六进制,0x12345678,他们最终就这样被ReadUInt32读取后:0x78563412

如果我使用的ReadBytes(4)方法中,我得到了预期的数组:

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

这是为什么?它只是方式.net代表内存中的提示?在不同的平台上(我正在运行64位Windows 7,.net 3.5 SP1)是否一样?

+0

您是否可以通过告诉我们如何修复它来平息我们的好奇心? :) – 2009-05-23 02:06:12

+1

当然:)实际上,字节顺序的方式并不重要,只要它跨平台(x64,x86)是一致的,我仍然可以提取我需要的位,我只需要更改我的位移动。据我所知,uint通常存储为little-endian,而不仅仅是ReadUInt32的uint构建,因此可以使一切变得更加简单。 – 2009-05-23 08:27:08

回答

8

这似乎是一个endianness问题。 The docs说ReadUint32读小端,所以第一个字节是最不重要的,所以它进入最低的内存位置。你的作家必须是大前锋?

BinaryWriter.Write(UInt32)says it writes也是小端。你的二进制数据源不是BinaryWriter吗?

基本上你需要做的,解决它,这是什么:

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

这把最低显著字节达24位,第2 LSB了8位,第3个LSB下8位,第4个LSB(MSB)下降24位。这样做在几个图书馆中都有涉及。

也许使用BitConverter会多一点明确:

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

是的,这与您的计算机硬件如何在内存中存储提示有关。它可以在不同的平台上有所不同,尽管大多数台式电脑应该是相同的。

这就是所谓的字节顺序 - 维基百科看到这里:

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

1

这是平台Endianess的问题。当你从一个流中读取数据时,你必须相应地读取它所写的字节。如果您在.Net中创建数据,那么.Net将正确读取它。

0

Generic BinaryReader and BinaryWriter Extensions,一个伟大的方式来处理通用铸造的非托管的方式。

对于VB。NET(只有安全的代码,也可以在C#实现)使用以下命令:

进口System.IO 进口System.Runtime.CompilerServices 进口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 

现在,您可以实现BitConverter的相同功能,BinaryWriter