2012-02-24 9 views
1

ストリームのバイト配列を圧縮しようとしています。 ExtendedStreamは、基本ストリーム(デフォルトではMemoryStream)とのインターフェイスを作ったクラスです。元のデータを取り出して圧縮し、元のデータのサイズと圧縮前のサイズとを比較すると、元のデータよりも小さいことがわかります。元のファイルは、GZip圧縮解除されたファイルよりも大きいです。

オリジナルの長さ:51695、圧縮された長さ:26014、解凍長さ:48685.

私が保管していたタイル(7バイト)。 System.IO.Compression名前空間で提供されているGZipクラスを使用して圧縮します。

public static ExtendedStream GZipDecompress(ExtendedStream stream) 
    { 
     ExtendedStream outStream = new ExtendedStream(); 
     GZipStream decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, true); 
     int b = -1; 

     while ((b = decompressStream.ReadByte()) != -1) 
     { 
      outStream.WriteByte((Byte)b); 
     } 

     outStream.Seek(0, SeekOrigin.Begin); 
     return outStream; 
    } 

    public static ExtendedStream GZipCompress(ExtendedStream stream) 
    { 
     ExtendedStream outStream = new ExtendedStream(); // base stream is a memorystream 
     GZipStream compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, true); 
     compressStream.Write(stream.ToArray(), 0, (int)stream.Length); 
     compressStream.Flush(); 
     outStream.Seek(0, SeekOrigin.Begin); 
     return outStream; 
    } 

希望の情報です。

+1

最初に、完了したらGZipStreamオブジェクトで.Disposeを呼び出す必要があります。また、書き込み時には、GZipStreamを破棄した後にoutStreamで.Flushを呼び出す必要があります。第3に、これが.NET4の場合は、入力ストリームの基本メンバーの.CopyToメソッドを使用して、入力から出力にデータをコピーします(ストリームが大きくなると拡大縮小しない.ToArrayを使用するのではなく)。 – Joe

+0

いいえ、解凍または圧縮するときに "outStream"でflushを呼び出す必要はありません。データはすでにストリームに入っています。 FlushingはMemoryStreamのため何もしません(そして、FYI MemoryStreamは何もしないようにFlushをオーバーライドします)。私はCopyToメソッドを念頭に置いておくつもりですが、GCは私のためにすべてのものを修正するだけです(私が知っているような駄目なデザインですが、これは設計目標#1ではありません)。 –

+1

@スーパ、いいえ。ジョーは正しい。あなたは**正式に圧縮ストリームを閉じたり/処分しなくてはなりません。それ以上のインバウンドがないことが分かっていない限り、フラッシュは空にできません。圧縮の制限。これは圧縮において絶対に重要です(私はそれを十分に強調したと思いますか?)。 Btw:これを行うには、個々のバイトをコピーすることは恐ろしい方法です。 –

答えて

1

圧縮ストリームを閉じる必要があります。

public static ExtendedStream GZipCompress(ExtendedStream stream) 
{ 
    ExtendedStream outStream = new ExtendedStream(); 
    using(var compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, false)) { 
     compressStream.Write(stream.GetBuffer(), 0, (int)stream.Length); 
    } 
    outStream.Seek(0, SeekOrigin.Begin); 
    return outStream; 
} 

注:通常、私が書き込みを行うにはCopyToの(または手動ループ)を使用しますが、これ以降であると思いメモリベースGetBufferを、それはあなたがやるまでは、原因が問題を阻止するために、すべてのデータを書き込むことはできません()は安いです。

あなたの解凍が簡単にできます。これの両方の部分Throught

decompressStream.WriteTo(outStream); 

、最大の問題は、(それがここであなたをかましている)あなたの使い捨てのオブジェクトを配置していません。 でなければなりません。それはAPIの要件です。外側ストリームを早期に処理しないようにするには、GZipStreamコンストラクタに "false"を渡します。例:

using(var decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, false)) { 
    decompressionStream.CopyTo(outStream); 
} 
+0

問題は、あなたが言ったように、実際の圧縮/解凍ストリームをフラッシュ/クローズしていないように見えました。 GetBufferの提案に感謝します。私に話をして問題の内容を実際に説明していないことを感謝します。 –

+0

@Supahええ、それは圧縮と暗号化のようなものの必要な機能です。データのブロックをバッファし、ブロック全体を一度に書き込むということです。これは、通常、書き込みを待っている残りのデータがあることを意味し、「Flush()」でさえもシフトできません。 –

関連する問題