正在从运行时已知类型的二进制文件中读取值
本文关键字:二进制文件 读取 类型 运行时 | 更新日期: 2023-09-27 18:29:23
我试图从二进制文件中读取一系列值,但直到运行时我才知道值类型是什么。
简化示例
我有一个10字节长的二进制文件。字节按顺序表示int
、float
和short
。我在编译时不知道这一点,但在运行时我确实知道,数组如下:
Type[] types = new Type[3];
types[0] = typeof(int);
types[1] = typeof(float);
types[2] = typeof(short);
问题
既然我有了这个列表,有没有一种方法可以使用这些信息快速读取文件中的值?我唯一能想到的方法是使用一个大的if
块,但它看起来真的很难看:
for (int i = 0; i < types.Length; i++)
{
if (types[i] == typeof(int))
{
int val = binaryfile.ReadInt32();
//... etc ...
}
else if (types[i] == typeof(float))
{
float val = binaryfile.ReadSingle();
//... etc ...
}
else if //... etc...
}
但这是丑陋和繁琐的。我想知道是否可以使用types
数组中的Type
信息以某种方式"自动化"这一点。
我尝试过的
我想到的一个想法是将原始字节读入数组,然后对字节数组执行转换。假设我的数组是这样的:
byte[] buf = new byte[10] {
0x40, 0xE2, 0x01, 0x00,
0x79, 0xE9, 0xF6, 0x42,
0x39, 0x30 };
其中分别包含int
、float
和short
值123456、123.456和12345。现在我可以做以下事情:
fixed (byte* bp = &buf[0])
{
int* ip = (int*)bp;
Console.WriteLine("int ptr: {0}", *ip);
}
这看起来效果不错,但有两个问题:
- 我不知道如何将
*ip
封送回托管域 我仍然无法使用我的类型列表,如下所示:
fixed (byte* bp = &buf[0]) { (types[0])* ip = ((types[0])*)bp; // both errors here Console.WriteLine("int ptr: {0}", *ip); }
这在所示的行上产生了两个编译时错误:
Error 1 Invalid expression term ')'
Error 2 ) expected
到目前为止,我只想尝试这些。
我希望有人能帮忙。我觉得我错过了一些能让我的生活轻松很多的简单的东西。
更新
我已经尝试了Peter Duniho的建议,它似乎运行得很好,尽管与大型if
块相比,性能受到了较小的影响。
以下是大约100 MB文件的一些结果(所有时间都以毫秒为单位):
彼得方法:
2025
2003
1954
1979
1958
if
块:
1531
1488
1486
1489
没有什么太重要的,尽管由于我计划处理更大的文件(在GB范围内),这几百毫秒加起来,所以我将坚持使用丑陋的if
块,直到我找到同样快的东西。
我不能100%确定我是否理解您实际想要解决的问题的哪一部分。但根据我想你在问的,我会这样做:
class Program
{
static readonly Dictionary<Type, Func<byte[], int, Tuple<object, int>>> _converters =
new Dictionary<Type, Func<byte[], int, Tuple<object, int>>>
{
{ typeof(int), (rgb, ib) =>
Tuple.Create((object)BitConverter.ToInt32(rgb, ib), sizeof(int)) },
{ typeof(float), (rgb, ib) =>
Tuple.Create((object)BitConverter.ToSingle(rgb, ib), sizeof(float)) },
{ typeof(short), (rgb, ib) =>
Tuple.Create((object)BitConverter.ToInt16(rgb, ib), sizeof(short)) },
};
static void Main(string[] args)
{
Type[] typeMap = { typeof(int), typeof(float), typeof(short) };
byte[] inputBuffer =
{ 0x40, 0xE2, 0x01, 0x00, 0x79, 0xE9, 0xF6, 0x42, 0x39, 0x30 };
int ib = 0, objectIndex = 0;
while (ib < inputBuffer.Length)
{
Tuple<object, int> current =
_converters[typeMap[objectIndex++]](inputBuffer, ib);
Console.WriteLine("Value: " + current.Item1);
ib += current.Item2;
}
}
}