views:

96

answers:

2

I am having an issue with this test function where I take an in memory string, compress it, and decompress it. The compression works great, but I can't seem to get the decompression to work.

//Compress
System.IO.MemoryStream outStream = new System.IO.MemoryStream();                
GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress);
mStream.Position = 0;
mStream.CopyTo(tinyStream);

//Decompress    
outStream.Position = 0;
GZipStream bigStream = new GZipStream(outStream, CompressionMode.Decompress);
System.IO.MemoryStream bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);

//Results:
//bigStreamOut.Length == 0
//outStream.Position == the end of the stream.

I believe that bigStream out should at least have data in it, especially if my source stream (outStream) is being read. is this a MSFT bug or mine?

+5  A: 

What happens in your code is that you keep opening streams, but you never close them.

  • In line 2, you create a GZipStream. This stream will not write anything to the underlying stream until it feels it’s the right time. You can tell it to by closing it.

  • However, if you close it, it will close the underlying stream (outStream) too. Therefore you can’t use mStream.Position = 0 on it.

You should always use using to ensure that all your streams get closed. Here is a variation on your code that works.

var inputString = "“ ... ”";
byte[] compressed;
string output;

using (MemoryStream outStream = new MemoryStream())
{
    using (GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress))
    using (MemoryStream mStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString)))
        mStream.CopyTo(tinyStream);
    compressed = outStream.ToArray();
}

// “compressed” now contains the compressed string.
// Also, all the streams are closed and the above is a self-contained operation.

using (MemoryStream inStream = new MemoryStream(compressed))
using (GZipStream bigStream = new GZipStream(inStream, CompressionMode.Decompress))
using (MemoryStream bigStreamOut = new MemoryStream())
{
    bigStream.CopyTo(bigStreamOut);
    output = Encoding.UTF8.GetString(bigStreamOut.ToArray());
}

// “output” now contains the uncompressed string.
Console.WriteLine(output);
Timwi
+1 good answer Timwi. Just to add to this, GZip has some internal buffering of data it needs to do in order to compress. It can't know that its done receiving data until you close it and therefore it doesn't spit out the last few bytes and decompression of the partial stream fails.
MerickOWA
+1  A: 

This is a known issue: http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx

I have changed your code a bit so this one works:

         MemoryStream mStream = new MemoryStream(new byte[100]);
        System.IO.MemoryStream outStream = new System.IO.MemoryStream();
        using (GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress))
        {
            mStream.CopyTo(tinyStream);           
        }
        byte[] bb = outStream.ToArray();

        //Decompress                
        GZipStream bigStream = new GZipStream(new MemoryStream(bb), CompressionMode.Decompress);
        System.IO.MemoryStream bigStreamOut = new System.IO.MemoryStream();
        bigStream.CopyTo(bigStreamOut);
Aliostad