为什么BinaryReader.ReadUInt32()反转位模式?

时间:2009-05-22 18:25:08

标签: .net 64-bit bit-manipulation 32-bit endianness

我正在尝试使用BinaryReader类读取二进制文件,我需要将其作为UInt32的块读取,然后在后面进行一些位移等。

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

例如,如果我有一个文件,其中前四个字节在十六进制中显示为0x12345678,则它们在被ReadUInt32读取后会以这样的结尾:0x78563412

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

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

这是为什么?这只是方式.net代表内存中的uint?在不同的平台上是否相同(我运行64位Windows 7,.net 3.5 sp1)?

6 个答案:

答案 0 :(得分:8)

是的,这与您的计算机硬件如何将uint存储在内存中有关。虽然大多数台式计算机应该是相同的,但它可以在不同平台上有所不同。

这称为字节序 - 请在此处查看维基百科:

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

答案 1 :(得分:8)

这似乎是一个endianness问题。 The docs表示ReadUint32以little-endian读取,因此第一个字节是最不重要的,因此它会进入最低内存位置。你的作家必须是大头?

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位,第二LSB向上移位8位,第三LSB向下移位8位,第四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);

答案 2 :(得分:3)

查看Jon Skeet的Endis *类的MiscUtil库,如EndianBinaryReader和EndianBitConverter。

http://www.yoda.arachsys.com/csharp/miscutil/

答案 3 :(得分:2)

Jon Skeet编写了一个带可配置字节序的BitConverter。您可能会发现它很有用。

http://www.yoda.arachsys.com/csharp/miscutil/

答案 4 :(得分:1)

这是平台Endianess的问题。当您从流中读取数据时,必须根据其写入的字节顺序读取它。如果您在.Net中创建数据,那么.Net将正确读取它。

答案 5 :(得分:0)

阅读Generic BinaryReader and BinaryWriter Extensions,这是处理非托管方式的通用投射的好方法。

对于VB.NET(仅限安全代码,也可以在C#中实现)使用以下内容:

导入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

您现在可以为BitConverterBinaryWriter等实现相同的功能。