wpf .NET GZipStream 解压产生空流

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11915612/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 04:56:47  来源:igfitidea点击:

.NET GZipStream decompress producing empty stream

c#.netwpfcompressiongzipstream

提问by Tom Hunter

I'm trying to serialize and compress a WPF FlowDocument, and then do the reverse - decompress the byte array and deserialize to recreate the FlowDocument - using the .NET GZipStreamclass. I'm following the example described on MSDN and I have the following test program:

我正在尝试序列化和压缩 WPF FlowDocument,然后执行反向操作 - 解压缩字节数组并反序列化以重新创建 FlowDocument - 使用 .NETGZipStream类。我正在按照 MSDN 上描述的示例进行操作,并且我有以下测试程序:

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);

However I get an exception at XamlReader.Loadline which is normal since the debug output tells that the uncompressed stream has a zero length.

但是XamlReader.Load,由于调试输出告诉未压缩流的长度为零,因此我在行中遇到异常。

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

Why doesn't the final uncompressedstream contain the original 123 bytes?

为什么最终uncompressed流不包含原始的 123 个字节?

(Please ignore the fact that the "compressed" byte array is bigger than the "uncompressed" byte array - I'll normally be working with much bigger flow documents)

(请忽略“压缩”字节数组比“未压缩”字节数组大的事实——我通常会处理更大的流文档)

回答by Jo?o Angelo

You need to close the GZipStreambefore getting the compressed bytes from the memory stream. In this case the closing is handled by the Disposecalled due to the using.

您需要GZipStream在从内存流中获取压缩字节之前关闭。在这种情况下,Dispose由于使用,关闭由被调用者处理。

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();
}

This works and you could even remove the usingfor the MemoryStreamsince it will be disposed by the GZipStreamunless you use the constructor overload that allows you to specify that the underlying stream should be left open. This implies with that code you are calling ToArrayon a disposed stream but that is allowed because the bytes are still available which makes disposing memory streams a bit weird but if you don't do it FXCop will annoy you.

这是有效的,您甚至可以删除usingfor ,MemoryStream因为它将由 the 处理,GZipStream除非您使用构造函数重载,该重载允许您指定底层流应保持打开状态。这意味着您正在调用ToArray已处理的流的代码,但这是允许的,因为字节仍然可用,这使得处理内存流有点奇怪,但如果您不这样做,FXCop 会惹恼您。

回答by Tom Hunter

Joao's answer did the trick. I've copied the full working example below. I've added a line to output compressedData.Length. Interestingly this outputs 218 bytes, whereas compressedStream.Lengthoutputs only 202 bytes. If you don't close the GZipStream before reading the byte array then compressedData.Lengthis 202. I'm not sure why closing the GZipStream gives you an extra 16 bytes..

Joao的回答成功了。我复制了下面的完整工作示例。我在 output 中添加了一行compressedData.Length。有趣的是,这输出了 218 个字节,而compressedStream.Length只输出了 202 个字节。如果您在读取字节数组之前不关闭 GZipStream,compressedData.Length则为 202。我不确定为什么关闭 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);
}

Debug output:

调试输出:

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

Note also the additional uncompressedStream.Position = 0;before the call to XamlReader.Load.

还要注意uncompressedStream.Position = 0;调用XamlReader.Load.

回答by Mina Samy

After you copy the decompressed bytes to your stream, you need to set its position to zero so that you can read it properly

将解压后的字节复制到流中后,需要将其位置设置为零,以便正确读取