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

发布于 2024-07-22 09:47:10 字数 517 浏览 9 评论 0原文

我正在尝试使用 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)?

I am trying to read a binary file with the BinaryReader class, and I need to read it in as blocks of UInt32, and then do some bit shifting etc. afterwords.

But, for some reason bit order is reversed when I use the ReadUInt32 method.

If I for example have a file where the first four bytes looks like this in hex, 0x12345678, they end up like this after being read by ReadUInt32: 0x78563412.

If I use the ReadBytes(4) method, I get the expected array:

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

Why is this? Is it just the way .net represents uints in memory? Is it the same across the different platforms (I am running 64bit Windows 7, .net 3.5 sp1)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

乱世争霸 2024-07-29 09:47:10

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

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

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

Yes, this has to do with how your computer hardware stores uints in memory. It can be different across different platforms, although most desktop computers should be the same.

This is called endianness -- see wikipedia here:

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

红衣飘飘貌似仙 2024-07-29 09:47:10

这似乎是一个 endianness 问题。 文档说 ReadUint32 以小端方式读取因此第一个字节是最低有效的,因此它位于最低的内存位置。 你的作者一定是大端字节序吗?

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);

This seems to be an endianness issue. The docs say ReadUint32 reads in little-endian so the first byte is the least-significant so it goes to the lowest memory location. Your writer must be big-endian?

BinaryWriter.Write(UInt32) says it writes little-endian too. Is your binary data source not BinaryWriter?

Essentially what you need to do to fix it is this:

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

This shifts the least-significant byte up 24 bits, the 2nd LSB up 8 bits, the 3rd LSB down 8 bits, and the 4th LSB (the MSB) down 24 bits. Doing this is covered in several libraries.

Perhaps using BitConverter would be a bit more clear:

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);
冬天旳寂寞 2024-07-29 09:47:10

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

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

Look into Jon Skeet's MiscUtil library for the Endian* classes, like EndianBinaryReader and EndianBitConverter.

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

花之痕靓丽 2024-07-29 09:47:10

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

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

Jon Skeet's written a BitConverter with configurable endian-ness. You might find it useful.

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

栖迟 2024-07-29 09:47:10

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

This is an issue of platform Endianess. When you read data from a stream you must read it accordingly to the endianess it was written as. If you created the data in .Net, then .Net will read it correctly.

躲猫猫 2024-07-29 09:47:10

阅读通用 BinaryReader 和 BinaryWriter 扩展,这是处理非托管泛型转换的好方法方式。

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

Imports 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

Read Generic BinaryReader and BinaryWriter Extensions, a great way to handle generic casting the unmanaged way.

For VB.NET (safe code only, can also be achieved in C#) use the following:

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

You can now implement the same functionality for BitConverter, for BinaryWriter etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文