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のバージョンがわからない。以前のバージョンでは、書き込み元のバッファーと同じサイズのウィンドウサイズを使用していました。したがって、あなたの場合、各整数を個別に圧縮しようとします。彼らは.NET4.0でそれを変更したと思いますが、それを検証していません。

いずれにせよ、あなたがしたいことは、GZipStream:の前にバッファリングされたストリームを作成することです。

//64KBのバッファを使用してファイルストリームを作成しますFileStreamfs= 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 Kバイトのチャンクでデータを取得し、圧縮のはるかに優れた仕事をすることができます。

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 に答える