GZipStream的功效

时间:2011-09-28 19:51:06

标签: c# gzipstream

我正在尝试将大的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();

2 个答案:

答案 0 :(得分: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 Kbyte块的形式获取数据,并且可以更好地进行压缩。

大于64KB的缓冲区不会给你更好的压缩。

答案 1 :(得分: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)
}