7

我正在尝试将大 UInt16 数组保存到文件中。positionCnt 大约 50000,stationCnt 大约 2500。直接保存,不使用 GZipStream,文件大约 250MB,可以通过外部 zip 程序压缩到 19MB。使用以下代码,文件为 507MB。我做错了什么?

GZipStream cmp = new GZipStream(File.Open(cacheFileName, FileMode.Create), CompressionMode.Compress);
BinaryWriter fs = new BinaryWriter(cmp);
fs.Write((Int32)(positionCnt * stationCnt));
for (int p = 0; p < positionCnt; p++)
{
    for (int s = 0; s < stationCnt; s++)
    {
       fs.Write(BoundData[p, s]);
    }
}
fs.Close();
4

2 回答 2

12

不确定您运行的是哪个版本的 .NET。在早期版本中,它使用的窗口大小与您从中写入的缓冲区大小相同。因此,在您的情况下,它将尝试单独压缩每个整数。我认为他们在 .NET 4.0 中改变了这一点,但尚未验证。

在任何情况下,您想要做的是在之前创建一个缓冲流GZipStream

// 创建具有 64 KB 缓冲区的文件流 FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None, 65536); GZipStream cmp = new GZipStream(fs, CompressionMode.Compress); ...

GZipStream cmp = new GZipStream(File.Open(cacheFileName, FileMode.Create), CompressionMode.Compress);
BufferedStream buffStrm = new BufferedStream(cmp, 65536);
BinaryWriter fs = new BinaryWriter(buffStrm);

这样,GZipStream获取 64 KB 块中的数据,并且可以更好地进行压缩。

大于 64KB 的缓冲区不会为您提供更好的压缩。

于 2011-09-28T20:41:35.703 回答
3

无论出于何种原因,在快速阅读 .Net 中的 GZip 实现时对我来说并不明显,性能对一次写入的数据量很敏感。我根据几种写入方式对您的代码进行了基准测试GZipStream,发现最有效的版本向磁盘写入了长步。

在这种情况下,权衡是内存,因为您需要根据您想要的步幅长度将其转换short[,]为:byte[]

using (var writer = new GZipStream(File.Create("compressed.gz"),
                                   CompressionMode.Compress))
{
    var bytes = new byte[data.GetLength(1) * 2];
    for (int ii = 0; ii < data.GetLength(0); ++ii)
    {
        Buffer.BlockCopy(data, bytes.Length * ii, bytes, 0, bytes.Length);
        writer.Write(bytes, 0, bytes.Length);
    }

    // Random data written to every other 4 shorts
    // 250,000,000 uncompressed.dat
    // 165,516,035 compressed.gz (1 row strides)
    // 411,033,852 compressed2.gz (your version)
}
于 2011-09-28T21:23:37.243 回答