8

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

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

例如,如果我有一个文件,其中前四个字节在 hex, 中看起来像这样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)?

4

6 回答 6

9

是的,这与您的计算机硬件在内存中存储 uint 的方式有关。尽管大多数台式计算机应该相同,但它在不同平台上可能会有所不同。

这称为字节序 - 请参阅此处的维基百科:

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

于 2009-05-22T18:30:23.117 回答
8

这似乎是一个字节顺序问题。 文档说 ReadUint32 以 little-endian 方式读取,因此第一个字节是最不重要的,因此它会到达最低的内存位置。你的作者一定是大端的?

BinaryWriter.Write(UInt32) 说它也写小端。你的二进制数据源不是 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);
于 2009-05-22T18:31:08.000 回答
3

查看 Jon Skeet 的 MiscUtil 库中的 Endian* 类,例如 EndianBinaryReader 和 EndianBitConverter。

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

于 2009-05-22T18:33:39.400 回答
2

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

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

于 2009-05-22T18:33:45.733 回答
1

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

于 2009-05-22T18:33:30.337 回答
0

阅读Generic BinaryReader 和 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、 forBinaryWriter等实现相同的功能。

于 2010-07-18T01:04:53.043 回答