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

时间:2022-09-01 10:18:32

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.

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

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

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

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.

例如,如果我有一个文件,其中前四个字节看起来像十六进制,0x12345678,它们在被ReadUInt32读取后会像这样结束:0x78563412。

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

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

[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)?

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

6 个解决方案

#1


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?

这似乎是一个字节序问题。文档说ReadUint32以little-endian读取,因此第一个字节是最不重要的,所以它进入最低内存位置。你的作家必须是大头?

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

BinaryWriter.Write(UInt32)说它也写了little-endian。你的二进制数据源不是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.

这将最低有效字节向上移位24位,第二LSB向上移位8位,第三LSB向下移位8位,第四LSB(MSB)向下移位24位。这样做包含在几个库中。

Perhaps using BitConverter would be a bit more clear:

也许使用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


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

#3


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

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

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

#4


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

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

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

#5


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.

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

#6


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

阅读Generic BinaryReader和BinaryWriter Extensions,这是处理非托管方式的通用转换的好方法。

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

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

Imports System.IO Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices

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.

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

#1


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?

这似乎是一个字节序问题。文档说ReadUint32以little-endian读取,因此第一个字节是最不重要的,所以它进入最低内存位置。你的作家必须是大头?

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

BinaryWriter.Write(UInt32)说它也写了little-endian。你的二进制数据源不是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.

这将最低有效字节向上移位24位,第二LSB向上移位8位,第三LSB向下移位8位,第四LSB(MSB)向下移位24位。这样做包含在几个库中。

Perhaps using BitConverter would be a bit more clear:

也许使用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


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

#3


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

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

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

#4


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

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

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

#5


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.

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

#6


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

阅读Generic BinaryReader和BinaryWriter Extensions,这是处理非托管方式的通用转换的好方法。

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

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

Imports System.IO Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices

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.

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