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
GZipStreambefore getting the compressed bytes from the memory stream. In this case the closing is handled by theDisposecalled due to the using.This works and you could even remove the
usingfor theMemoryStreamsince it will be disposed by theGZipStreamunless 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 callingToArrayon 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.