7

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

private T[,] m_data;

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

我四处寻找自定义序列化程序,但没有看到任何处理多维泛型数组的方法。在序列化成功后,我还在内存流的字节数组上尝试了内置 .net 压缩,但没有我希望的那么快/压缩。

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

任何关于最佳方法的建议将不胜感激,或者链接到显示如何处理多维通用数组的序列化的资源 - 正如我发现的现有示例所提到的那样,我发现不支持这种结构。

4

4 回答 4

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 编辑] 我希望您不会被编辑冒犯,但统一重复的 Range(0,width) 会极大地扭曲事物;改成:

        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.txt40MBtemp_zipped.txt和 62MB。没那么吸引人...

于 2008-10-22T00:00:58.100 回答
0

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

于 2008-10-21T22:14:04.977 回答
0

你能定义“大”吗?1000x10000xint 示例(另一篇文章)的大小为 40Mb;1000x10000x4 字节 (=int) 为 38MB。随着开销的增加,这并不可怕。

T 可能是什么类型的数据?只是原语?我在想我可能可以编辑protobuf-net以支持矩形数组*- 但为了保持某种线路兼容性,我们可能需要每个元素一个标题(一个字节) - 即 1000x10000 示例的 9MB 开销。

float这对于诸如,等之类的东西可能是不值得的double(因为它们逐字存储在“协议缓冲区”下) - 但可能会int因为它如何打包整数而节省一些东西......(特别是如果他们倾向于在较小的一侧[幅度])。最后,如果 T 实际上是Personetc 之类的对象,那么它应该比二进制序列化好很多,因为它非常擅长打包对象。

在矩形阵列中插入鞋拔并非易事,但如果您有兴趣尝试,请告诉我。

*:目前不支持,因为“协议缓冲区”规范不支持它们,但我们可以解决这个问题......

于 2008-10-22T05:56:28.663 回答
0

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

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

于 2009-09-25T14:54:08.703 回答