我正在解析一个二进制文件格式。它以一种自然适合c#的uint类型的方式编码一个使用四个字节的整数。从字节数组中解开一个整数的习惯用c#是什么?
什么是实现这一功能的最C#/惯用方式:
uint ReadUint(byte[] buffer);
假定缓冲区包含4个元素。完整的答案可能会考虑由文件中的小/大端假设引起的一些常见字节顺序,并记录它选择解析的一个或多个字节顺序。
我正在解析一个二进制文件格式。它以一种自然适合c#的uint类型的方式编码一个使用四个字节的整数。从字节数组中解开一个整数的习惯用c#是什么?
什么是实现这一功能的最C#/惯用方式:
uint ReadUint(byte[] buffer);
假定缓冲区包含4个元素。完整的答案可能会考虑由文件中的小/大端假设引起的一些常见字节顺序,并记录它选择解析的一个或多个字节顺序。
最基本的(但有点危险重新字节顺序)为:
return BitConverter.ToUInt32(buffer, 0);
比高于其他,移位是好的(根据你自己的回复) - 或者你可以使用Jon的EndianBitConverter in MiscUtil,该手柄翻译。
(编辑)
小尾数位移版本我在protobuf网用的是漂亮的,很多相同的版本 - 我刚刚看了他们按升序排列,使用按位(不是数字)此外:
return ((uint)buffer[0])
| (((uint)buffer[1]) << 8)
| (((uint)buffer[2]) << 16)
| (((uint)buffer[3]) << 24);
正如有人在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;
}
这解析维基百科声称在little-endian的方式设计了一个格式,就在i386上运行的.NET实现/ Vista的
假设你想读他们的数据流(如您的代码会建议) 我会说,这是非常接近的事实上的标准方式:
MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();
我通常会为此使用BitConverter类。在你的情况下,BitConverter.ToUInt32()方法。
byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);
简单的方法是
int val = System.BitConverter.ToInt32(buffer, 0);
这使用当前系统的字节序,这可能会或可能不是你想要的是。
这个回复实际上是一个扩展的评论(因此wiki)比较BitConverter的性能和bitshifting使用+ 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;
}
}
注意,按位|将比数字更简单+ ...查看我的(更新)答案为例。 – 2009-05-18 20:54:36
为什么会|比+更简单吗? – 2009-05-18 20:58:34
我的理解是,按位操作涉及的CPU比数学工作要少,因为它只是应用了位掩码。在“checked”上下文中可能会有额外的溢出检查等(注意默认情况下C#是“unchecked”)。 – 2009-05-18 21:01:12