优化多维通用数组的二进制序列化

时间:2008-10-21 22:08:29

标签: c# .net serialization binary

我有一个我需要二进制序列化的类。该类包含一个字段,如下所示:

private T[,] m_data;

这些多维数组可能相当大(数十万个元素)和任何原始类型。当我在一个对象上尝试标准的.net序列化时,写入磁盘的文件很大,我认为.net存储了很多关于元素类型的重复数据,可能没有那么高效。

我一直在寻找自定义序列化器,但是还没有看到任何处理多维通用数组的事情。我已经在序列化之后对内存流的字节数组进行了内置的.net压缩试验,取得了一些成功,但没有像我希望的那样快速/压缩。

我的问题是,我是否应该尝试编写自定义序列化程序,以便为适当的类型优化序列化此数组(这看起来有点令人生畏),还是应该使用标准的.net序列化并添加压缩?

关于最佳方法的任何建议都是最受欢迎的,或链接到资源显示如何处理多维通用数组的序列化 - 如上所述existing examples我发现不支持这样的结构。

4 个答案:

答案 0 :(得分:5)

这就是我想出的。下面的代码生成一个int [1000] [10000]并使用BinaryFormatter将其写入2个文件 - 一个压缩,一个不压缩。

压缩文件是1.19 MB(1,255,339字节) 解压缩为38.2 MB(40,150,034字节)

        int width = 1000;
        int height = 10000;
        List<int[]> list = new List<int[]>();
        for (int i = 0; i < height; i++)
        {
            list.Add(Enumerable.Range(0, width).ToArray());
        }
        int[][] bazillionInts = list.ToArray();
        using (FileStream fsZ = new FileStream("c:\\temp_zipped.txt", FileMode.Create))
        using (FileStream fs = new FileStream("c:\\temp_notZipped.txt", FileMode.Create))
        using (GZipStream gz = new GZipStream(fsZ, CompressionMode.Compress))
        {
            BinaryFormatter f = new BinaryFormatter();
            f.Serialize(gz, bazillionInts);
            f.Serialize(fs, bazillionInts);
        }

我想不出更好/更简单的方法来做到这一点。拉链版非常紧凑。

我会使用BinaryFormatter + GZipStream。制作定制的东西根本不会很有趣。


[由MG编辑] 我希望你不会被编辑所冒犯,但是统一的重复范围(0,宽度)正在大大扭曲事物;改为:

        int width = 1000;
        int height = 10000;
        Random rand = new Random(123456);
        int[,] bazillionInts = new int[width, height];
        for(int i = 0 ; i < width;i++)
            for (int j = 0; j < height; j++)
            {
                bazillionInts[i, j] = rand.Next(50000);
            }

尝试一下;你会看到temp_notZipped.txt为40MB,temp_zipped.txt为62MB。不太吸引人......

答案 1 :(得分:0)

最佳代码长度/输出大小比率是使用BitConverter对数组进行编码,将所有元素转换为紧凑的二进制格式。我知道这是手册,但与.NET二进制序列化相比,可以节省80-90%的空间。

答案 2 :(得分:0)

你能定义“大”吗? 1000x10000xint示例(另一篇文章)出现在40Mb;和1000x10000x4字节(= int)是38MB。随着管理费用的增加,这并不可怕。

T可能是哪种数据?只是灵长类动物? 我想我可以编辑protobuf-net以支持矩形数组* - 但为了保持某种线路兼容性,我们可能需要每个元素的头部(一个字节) < / em> - 即1000x10000示例的9MB开销。

floatdouble之类的东西来说,这可能是不值得的(因为它们是在“协议缓冲区”下逐字存储的) - 但是{{1}可能会有节省仅仅因为它包装内部的方式...(特别是如果它们倾向于较小的一侧[幅度])。最后,如果T实际上是int等对象,那么它应该比 lot 更好于二进制序列化,因为它非常擅长打包对象。

矩形阵列中的鞋角不是一件容易的事,但请告诉我这是否是你想要尝试的东西。

Person:由于“协议缓冲区”规范不支持它们,但目前还没有,但我们可以解决这个问题......

答案 3 :(得分:0)

需要有这么多关于类型的数据的原因是你的T数组可以是任何类型,但更具体地说,T可以是SomeBaseClass类型,你仍然可以在该数组中存储SomeDerivedClass,并且反序列化器需要知道这一点。

但是这些冗余数据使其成为压缩的良好候选者,正如其他人所指出的那样。