11

私は WPF をシリアル化して圧縮しようとしています .NETクラスFlowDocumentを使用して、バイト配列を解凍し、逆シリアル化して FlowDocument を再作成します。GZipStreamMSDN で説明されている例に従っており、次のテスト プログラムがあります。

var flowDocumentIn = new FlowDocument();
flowDocumentIn.Blocks.Add(new Paragraph(new Run("Hello")));
Debug.WriteLine("Compress");
byte[] compressedData;
using (var uncompressed = new MemoryStream())
{
    XamlWriter.Save(flowDocumentIn, uncompressed);
    uncompressed.Position = 0;
    using (var compressed = new MemoryStream())
    using (var compressor = new GZipStream(compressed, CompressionMode.Compress))
    {
        Debug.WriteLine(" uncompressed.Length: " + uncompressed.Length);
        uncompressed.CopyTo(compressor);
        Debug.WriteLine(" compressed.Length: " + compressed.Length);
        compressedData = compressed.ToArray();
    }
}

Debug.WriteLine("Decompress");
FlowDocument flowDocumentOut;
using (var compressed = new MemoryStream(compressedData))
using (var uncompressed = new MemoryStream())
using (var decompressor = new GZipStream(compressed, CompressionMode.Decompress))
{
    Debug.WriteLine(" compressed.Length: " + compressed.Length);
    decompressor.CopyTo(uncompressed);
    Debug.WriteLine(" uncompressed.Length: " + uncompressed.Length);
    flowDocumentOut = (FlowDocument) XamlReader.Load(uncompressed);
}

Assert.AreEqual(flowDocumentIn, flowDocumentOut);

ただしXamlReader.Load、デバッグ出力で圧縮されていないストリームの長さがゼロであることが示されているため、行で例外が発生しますが、これは正常です。

Compress
 uncompressed.Length: 123
 compressed.Length: 202
Decompress
 compressed.Length: 202
 uncompressed.Length: 0

uncompressed最終ストリームに元の 123 バイトが含まれていないのはなぜですか?

(「圧縮された」バイト配列が「圧縮されていない」バイト配列よりも大きいという事実を無視してください。通常は、はるかに大きなフロー ドキュメントで作業します)

4

3 に答える 3

15

GZipStreamメモリ ストリームから圧縮されたバイトを取得する前に、を閉じる必要があります。この場合、クローズはDisposeusing のために呼び出されたものによって処理されます。

using (var compressed = new MemoryStream())
{
    using (var compressor = new GZipStream(compressed, CompressionMode.Compress))
    {
        uncompressed.CopyTo(compressor);
    }
    // Get the compressed bytes only after closing the GZipStream
    compressedBytes = compressed.ToArray();
}

これは機能し、基になるストリームを開いたままにする必要があることを指定できるコンストラクターのオーバーロードを使用しない限り、 forによって破棄されるため、 usingfor を削除することもできます。これは、破棄されたストリームで呼び出しているコードを意味しますが、バイトがまだ利用可能であるため、メモリストリームの破棄が少し奇妙になりますが、そうしないと FXCop に悩まされます。MemoryStreamGZipStreamToArray

于 2012-08-11T18:47:49.973 に答える
4

Joaoの答えはうまくいきました。以下の完全な動作例をコピーしました。output に行を追加しましたcompressedData.Length。興味深いことに、これは 218 バイトを出力しますが、compressedStream.Length202 バイトしか出力しません。バイト配列を読み取る前に GZipStream を閉じないと、 compressedData.Length202 になります。なぜ GZipStream を閉じると余分な 16 バイトが得られるのかわかりません。

var flowDocumentIn = new FlowDocument();
flowDocumentIn.Blocks.Add(new Paragraph(new Run("Hello")));

Debug.WriteLine("Compress");

byte[] compressedData;

using (var uncompressedStream = new MemoryStream())
{
    XamlWriter.Save(flowDocumentIn, uncompressedStream);
    uncompressedStream.Position = 0;
    using (var compressedStream = new MemoryStream())
    {
        using (var gZipCompressor = new GZipStream(compressedStream, CompressionMode.Compress))
        {
            Debug.WriteLine(" uncompressedStream.Length: " + uncompressedStream.Length);
            uncompressedStream.CopyTo(gZipCompressor);
            Debug.WriteLine(" compressedStream.Length: " + compressedStream.Length);
        }
        compressedData = compressedStream.ToArray();
    }
}

Debug.WriteLine(" compressedData.Length: " + compressedData.Length);

Debug.WriteLine("Decompress");

FlowDocument flowDocumentOut;

using (var compressedStream = new MemoryStream(compressedData))
using (var uncompressedStream = new MemoryStream())
{
    using (var gZipDecompressor = new GZipStream(compressedStream, CompressionMode.Decompress))
    {
        Debug.WriteLine(" compressedStream.Length: " + compressedStream.Length);
        gZipDecompressor.CopyTo(uncompressedStream);
        Debug.WriteLine(" uncompressedStream.Length: " + uncompressedStream.Length);
    }
    uncompressedStream.Position = 0;
    flowDocumentOut = (FlowDocument)XamlReader.Load(uncompressedStream);
}

デバッグ出力:

Compress
 uncompressedStream.Length: 123
 compressedStream.Length: 202
 compressedData.Length: 218
Decompress
 compressedStream.Length: 218
 uncompressedStream.Length: 123

uncompressedStream.Position = 0;への呼び出しの前の追加にも注意してくださいXamlReader.Load

于 2012-08-11T20:59:59.113 に答える
0

圧縮解除されたバイトをストリームにコピーしたら、その位置をゼロに設定して正しく読み取れるようにする必要があります

于 2015-12-23T12:59:21.257 に答える