0

我正在尝试从二进制文件中读取一系列值,但直到运行时我才知道值类型是什么。

简化示例

我有一个 10 字节长的二进制文件。字节依次表示 an int、 afloat和 a 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...
        }

但这是丑陋和麻烦的。我想知道我是否可以使用数组中的Type信息types以某种方式“自动化”这个。

我试过的

我想到的一个想法是将原始字节读入数组,然后对字节数组执行转换。因此,假设我的数组如下所示:

        byte[] buf = new byte[10] {
            0x40, 0xE2, 0x01, 0x00,
            0x79, 0xE9, 0xF6, 0x42,
            0x39, 0x30 };

这分别包含intfloatshort值 123456、123.456 和 12345。现在我可以执行以下操作:

        fixed (byte* bp = &buf[0])
        {
            int* ip = (int*)bp;
            Console.WriteLine("int ptr: {0}", *ip);
        }

这似乎运作良好,但有两个问题:

  1. 我不知道如何编组*ip回托管域。
  2. 我仍然无法使用我的类型列表,如下:

        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块,直到我找到一样快的东西。

4

1 回答 1

1

我不是 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;
        }
    }
}
于 2014-11-06T06:07:07.150 回答