【问题标题】:Why does BinaryReader.ReadUInt32() reverse the bit pattern?为什么 BinaryReader.ReadUInt32() 反转位模式?
【发布时间】:2010-10-28 07:25:31
【问题描述】:

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

【问题讨论】:

  • 你能告诉我们你是如何解决它的吗? :)
  • 当然 :) 实际上,字节顺序是哪种方式并不重要,只要它跨平台(x64,x86)一致,我仍然可以提取我需要的位,我只是必须改变我的位移。据我所知,uint 通常存储为 little-endian,而不仅仅是由 ReadUInt32 构建的 uint,因此这让一切变得更容易。

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


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    BinaryWriter.Write(UInt32) says it writes little-endian 也是。你的二进制数据源不是 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);
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • lol 1 分钟内 3 个维基百科链接。应该有一个徽章!
          【解决方案6】:

          阅读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
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-11-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-07-20
            • 2017-08-15
            相关资源
            最近更新 更多