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 GZipStream
class. I'm following the example described on MSDN and I have the following test program:
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.Load
line which is normal since the debug output tells that the uncompressed stream has a zero length.
Compress
uncompressed.Length: 123
compressed.Length: 202
Decompress
compressed.Length: 202
uncompressed.Length: 0
Why doesn't the final uncompressed
stream contain the original 123 bytes?
(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)
You need to close the GZipStream
before getting the compressed bytes from the memory stream. In this case the closing is handled by the Dispose
called due to the using.
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 using
for the MemoryStream
since it will be disposed by the GZipStream
unless 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 ToArray
on 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.
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.Length
outputs only 202 bytes. If you don't close the GZipStream before reading the byte array then compressedData.Length
is 202. I'm not sure why closing the GZipStream gives you an extra 16 bytes..
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With