从字节数组中解包整数的惯用c#是什么?

时间:2009-05-18 20:42:19

标签: c# parsing

我正在解析二进制文件格式。它使用四个字节对一个整数进行编码,其方式自然适合c#的uint类型。

实现此功能的最多C#/惯用方法是什么:

uint ReadUint(byte[] buffer);

假设缓冲区包含4个元素。完整的答案可能会考虑文件中的小/大端假设引起的一些常见字节排序,并记录它选择解析的一个或多个。

7 个答案:

答案 0 :(得分:5)

最基本的(但有点危险的重新结束)是:

return BitConverter.ToUInt32(buffer, 0);

除了比特移位很好(根据你自己的回复) - 或者你可以使用处理翻译的Jon EndianBitConverter in MiscUtil

(编辑)

我在protobuf-net中使用的little-endian位移版本与你的版本非常相似 - 我只是按升序读取它们并使用按位(不是数字)加法:

return ((uint)buffer[0])
        | (((uint)buffer[1]) << 8)
        | (((uint)buffer[2]) << 16)
        | (((uint)buffer[3]) << 24);

答案 1 :(得分:2)

我通常会使用BitConverter类。在您的情况下使用BitConverter.ToUInt32()方法。

答案 2 :(得分:2)

这个回复实际上是一个扩展评论(因此维基)比较BitConverter和使用+ vs |的比特转换的性能;它仅适用于微优化!!

结果第一:

BitConverter: 972ms, chk=1855032704
Bitwise: 740ms, chk=1855032704
ReadLength: 1316ms, chk=1855032704

或者如果调整结果以允许非零基本偏移:

BitConverter: 905ms, chk=1855032704
Bitwise: 1058ms, chk=1855032704
ReadLength: 1244ms, chk=1855032704

代码:

using System;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        byte[] buffer = BitConverter.GetBytes((uint)123);
        const int LOOP = 50000000;
        uint chk = 0;
        var watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += BitConverter.ToUInt32(buffer, 0);
        }
        watch.Stop();
        Console.WriteLine("BitConverter: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += Bitwise(buffer);
        }
        watch.Stop();
        Console.WriteLine("Bitwise: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += ReadLength(buffer);
        }
        watch.Stop();
        Console.WriteLine("ReadLength: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        Console.ReadKey();
    }
    static uint Bitwise(byte[] buffer)
    {
        return ((uint)buffer[0])
            | (((uint)buffer[1]) << 8)
            | (((uint)buffer[2]) << 16)
            | (((uint)buffer[3]) << 24);
    }
    static uint ReadLength(byte[] buffer)
    {
        uint result = ((uint)buffer[3]) << 24;
        result += ((uint)buffer[2]) << 16;
        result += ((uint)buffer[1]) << 8;
        result += buffer[0];
        return result;
    }
}

答案 3 :(得分:1)

作为来自C的人,这就是我目前实现此功能的方式:

static uint ReadLength(byte[] buffer)
{
    uint result = ((uint) buffer[3]) << 24;
    result |= ((uint) buffer[2]) << 16;
    result |= ((uint) buffer[1]) << 8;
    result |= buffer[offset];
    return result;
}

这解析了维基百科声称以小端方式布局的格式,在i386 / Vista上运行的.net实现

答案 4 :(得分:0)

假设您想要读取它们的流(正如您的代码所建议的那样) 我会说这非常接近事实上的标准方式:

MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();

答案 5 :(得分:0)

byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);

使用BitConverter Class

答案 6 :(得分:0)

最简单的方法就是

int val  = System.BitConverter.ToInt32(buffer, 0);

这使用当前的系统字节序,可能是您想要的也可能不是。