我正在使用BinaryReader读取文件。
我想要在地址0x37E处提取数据,但它是int24。所以即使我读了3个字节,我也无法将其转换为int24。
你有什么建议吗?
我正在使用C#并正在处理STFS包。
答案 0 :(得分:2)
为了将字节数组转换为int24,您需要知道数据的字节顺序。这意味着:11 22 33
应该表示0x112233
或0x332211
的信息。
根据此字节顺序,您可以转换
等数据int24 result_bigendian = array[0] * 65536 + array[1] * 256 + array[2] // (1)
或
int24 result_littleendian = array[2] * 65536 + array[1] * 256 + array[0] // (2)
(相应的
int24 result_littleendian = array[0] + array[1] * 256 + array[2] * 65536 // (3)
如果你愿意的话;注意(1))
的区别我不知道C#;可能有更简单的方法来达到目标。
答案 1 :(得分:2)
对于 signed int24,little endian 使用:
int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;
对于签署的int24,big endian 使用:
int num = (sbyte)array[0] << 16 | array[1] << 8 | array[2];
对于 unsigned int24,little endian 使用:
int num = array[0] | array[1] << 8 | array[2] << 16;
对于 unsigned int24,big endian 使用:
int num = array[0] << 16 | array[1] << 8 | array[2];
请注意,对于任何 signed int,little endian n 字节,只需列表所有字节,连接他们逐个使用'|', shift ,然后添加(sbyte)到最后一个字节以使其签名:
var num = array[0] | array[1] << 8 | array[2] << 16 | ... | (sbyte)array[n] << 8*n;
对于 big endian ,只需撤消转移顺序:
var num = array[n] | array[n-1] << 8 | array[n-2] << 16 | ... | (sbyte)array[0] << 8*n;
或者,当然,或者:
var num = (sbyte)array[0] << 8*n | array[1] << 8*(n-1) | ... | array[0];
你必须确保(sbyte)与最高位字节(最后一个字节,如果是小端,第一个字节,如果是大端)得到C#为int创建符号。
当然,对于 unsigned int ,只需删除(sbyte)。
最后一件事...... 数组可以是 byte [] 或 int [] 。所以你可以这样做:
var num = stream.ReadByte() | stream.ReadByte() << 8 | (sbyte)stream.ReadByte() << 16;
流是 System.IO.Stream 。
答案 2 :(得分:1)
我前段时间已经为这个问题写了一个扩展方法。
public enum Endian : int {
Little,
Big
}
public static int ToInt32(this byte[] buffer, Endian endian = Endian.Little) {
if (buffer.Length < 1 || buffer.Length > 4)
throw new ArgumentException(" ... ");
if (endian == Endian.Big)
buffer.Reverse();
int sum = 0;
for (int i = buffer.Length - 1; i > -1; --i)
sum += (buffer[i] << (i << 3));
if ((buffer[buffer.Length - 1] & 0x80) == 0x80)
sum |= (0xFFFFFF << (buffer.Length << 3));
return sum;
}
public static unsafe void Reverse(this byte[] buffer) {
fixed (byte* b = buffer) {
byte* s, e;
s = b;
e = b + buffer.Length - 1;
byte t;
while (s < e) {
t = *s;
*s = *e;
*e = t;
++s;
--e;
}
}
}
Endian枚举 和 反向方法 由ToInt32方法用于Endian目的。
ToInt32方法有一些很好的好处:
1。这是一种扩展方法,因此您可以使用byte []对象调用它。
byte[] x = { 0xFF, 0xFF, 0x7F };
int value = x.ToInt32();
2. 它能够将字节数组转换为两个字节顺序。
byte[] x = { 0x12, 0x34, 0x56 };
int valueLittle = x.ToInt32(Endian.Little); // Return 5,649,426
int valueBig = x.ToInt32(Endian.Big); // Return 1,193,046
3。它负责符号位。
byte[] x = { 0x00, 0x00, 0x80 };
x.ToInt32(); // Return -8,388,608
x.ToInt32(Endian.Big); // Return 128
我试图尽可能快地制作方法。一些基准和速度对我有好处。
希望这个解决方案有助于让生活更轻松。 ;)
答案 3 :(得分:0)
为了补充@glglgl答案,在C#中您可以尝试以下方法:
public int ReadInt24(byte[] array, int pos)
{
if(array == null || array.Length < 3)
return -1; //some invalid value
if (BitConverter.IsLittleEndian)
return ((array[2]) + (array[1] * 256) + (array[0] * 65536));
else
return ((array[0]) + (array[1] * 256) + (array[2] * 65536));
}
属性BitConverter.IsLittleEndian将告知当前的Endianness
表示存储数据的字节顺序(“endianness”) 这种计算机体系结构。
答案 4 :(得分:0)
对于signed int24使用:
int num = array[0] | array[1] << 8 | (sbyte)array[2] << 16;