2

私は間違いなく非常に明白な何かを見逃していますが、2番目のケースで圧縮率がはるかに優れている理由を誰か説明できますか?!

ケース 1: 圧縮率が非常に低く、サイズが大きくなることもあります。

using (var memoryStream = new System.IO.MemoryStream())
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress))
{
  new BinaryFormatter().Serialize(gZipStream, obj);
  gZipStream.Close();
  return memoryStream.ToArray();
}

ケース 2: 圧縮が大幅に改善され、サイズが大きくなりませんでした。

using (MemoryStream msCompressed = new MemoryStream())
using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress))
using (MemoryStream msDecompressed = new MemoryStream())
{
  new BinaryFormatter().Serialize(msDecompressed, obj);
  byte[] byteArray = msDecompressed.ToArray();

  gZipStream.Write(byteArray, 0, byteArray.Length);
  gZipStream.Close();
  return msCompressed.ToArray();
}

私はミラー化された解凍を行いましたが、どちらの場合も問題なくソース オブジェクトに逆シリアル化できます。

ここにいくつかの統計があります:

UncSize: 58062085B、Comp1: 46828139B、0.81%

UncSize: 58062085B、Comp2: 31326029B、0.54%

UncSize: 7624735B、Comp1: 7743947B、1.02%

UncSize: 7624735B、Comp2: 5337522B、0.70%

UncSize: 1237628B、Comp1: 1265406B、1.02%

UncSize: 1237628B、Comp2: 921695B、0.74%

4

1 に答える 1

7

使用している.NETのバージョンはわかりません。4.0より前のバージョンGZipStreamでは、書き込みごとにデータを圧縮します。つまり、送信するバッファを圧縮します。最初の例では、Serializeメソッドはストリームに非常に小さなバッファーを書き込む可能性があります(一度に1つのフィールド)。2番目の例でSerializeは、オブジェクト全体をメモリストリームにシリアル化してから、メモリストリームのバッファGZipStreamを1つの大きなチャンクに書き込みます。GZipStream使用するバッファが大きい(64Kが最適に近い)場合は、はるかに優れています。

これは、.NET4.0でも当てはまる可能性があります。テストしたかどうかは覚えていません。

私が過去にこれを処理した方法は、BufferedStreamを使用することです:

using (var mstream = new MemoryStream())
{
    using (var bstream = new BufferedStream(new GZipStream(mstream, CompressionMode.Compress), 65536))
    {
        new BinaryFormatter().Serialize(btream, obj);
    }
    return mstream.ToArray();
}

このようにして、コンプレッサーは64Kのバッファーを取得して動作します。

.NET 4.0より前は、64Kを超えるバッファを提供するメリットはありませんでしたGZipStream。.NET 4.0のコンプレッサーは、より大きなバッファーでより良い圧縮を実行できることを示す情報を見てきました。しかし、私はそれを自分でテストしていません。

于 2012-08-28T14:18:19.560 に答える