如何简化从BinaryReader进行网络字节序转换?

9

System.IO.BinaryReader以小端格式读取值。

我有一个C#应用程序,连接到服务器端的专有网络库。服务器端以网络字节顺序发送所有内容,正如人们所期望的那样,但我发现在客户端处理这些内容很麻烦,特别是对于无符号值。

UInt32 length = (UInt32)IPAddress.NetworkToHostOrder(reader.ReadInt32());

这是我想到的唯一从流中获取正确无符号值的方法,但这似乎既笨拙又丑陋。我还没有测试是否只会剪切掉高位值,以至于我必须使用有趣的BitConverter技巧。
除了编写整个包装器来避免每次读取时进行这些丑陋的转换之外,我是否错过了某种方法?似乎应该在读取器上有一个字节序选项,使得像这样的事情更简单,但我还没有找到任何东西。

现在这并没有什么帮助,但我已经创建了一个连接工单,以支持BinaryReder/Writer开箱即用的Bigendian。请在此处投票支持它。 - Martin Brown
当字节可以表示本机整数时,原始代码是否能正常工作? - Denise Skidmore
@Denise Skidmore - 是的,它确实有。请查看 .net 源代码。 - Thorham
2个回答

7

没有内置的转换器。以下是我的包装器(正如您所看到的,我只实现了我需要的功能,但结构很容易根据您的喜好更改):

/// <summary>
/// Utilities for reading big-endian files
/// </summary>
public class BigEndianReader
{
    public BigEndianReader(BinaryReader baseReader)
    {
        mBaseReader = baseReader;
    }

    public short ReadInt16()
    {
        return BitConverter.ToInt16(ReadBigEndianBytes(2), 0);
    }

    public ushort ReadUInt16()
    {
        return BitConverter.ToUInt16(ReadBigEndianBytes(2), 0);
    }

    public uint ReadUInt32()
    {
        return BitConverter.ToUInt32(ReadBigEndianBytes(4), 0);
    }

    public byte[] ReadBigEndianBytes(int count)
    {
        byte[] bytes = new byte[count];
        for (int i = count - 1; i >= 0; i--)
            bytes[i] = mBaseReader.ReadByte();

        return bytes;
    }

    public byte[] ReadBytes(int count)
    {
        return mBaseReader.ReadBytes(count);
    }

    public void Close()
    {
        mBaseReader.Close();
    }

    public Stream BaseStream
    {
        get { return mBaseReader.BaseStream;  }
    }

    private BinaryReader mBaseReader;
}

ReadBigEndianBytes基本上是干脏活的,然后将其传递给BitConverter。如果读取大量字节,则会出现明显的问题,因为这会导致大量内存分配。


1
注意:Array.Reverse()会原地将数组顺序翻转。 - Dr. Funk
读取单个字节可能会非常慢。最好一次性尽可能多地读取字节。此外,使用传统的位运算转换解决方案可以最快地进行大小端转换。当然,对于少量数据来说这不是什么大问题。 - Thorham

1
我构建了一个定制的BinaryReader来处理所有这些。它作为我的Nextem库的一部分可用。它还有一种非常简单的方法来定义二进制结构,我认为这将对你有所帮助——请查看示例。
注意:目前仅在SVN中,但非常稳定。如果您有任何问题,请通过电子邮件与我联系:cody_dot_brocious_at_gmail_dot_com。

谢谢。我有点希望避免引入额外的库依赖,因为整个东西应该是相当小和简单的,但我会记住它的。不过很高兴看到许可证是明确的。 :) - Zach Lute
啊,我明白了。如果你选择这样做,希望它能为你工作。是的,我选择公共领域正是出于这个原因——我希望人们能够尽情地使用它,而组件足够小,不必担心补丁的问题 :) - Serafina Brocious

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接