GZipStream compression not working
Asked Answered
S

1

7

I'm trying to read in a file and compress it using GZipStream, like this:

using (var outStream = new MemoryStream())
{
    using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress))
        {
            fileStream.CopyTo(gzipStream);

            Debug.WriteLine(
                "Compressed from {0} to {1} bytes", 
                fileStream.Length, 
                outStream.Length);

            // "outStream" is utilised here (persisted to a NoSql database).
        }
    }
} 

The problem is that outStream.Length always shows 10 bytes. What am I doing wrong?

I've tried calling gzipStream.Close() after the fileStream.CopyTo line (as suggested in other forums) but this seems to close outStream too, so the subsequent code that uses it falls over.

Stylographic answered 6/12, 2013 at 12:6 Comment(1)
According to [the msdn][1] there's no reason to trust too much the Stream.length proprety, which may or may not be implemented. Did you check by other means that the outstream obtained is incorrect ? [1]: msdn.microsoft.com/en-us/library/…Synergistic
P
6

MSDN says: The write operation might not occur immediately but is buffered until the buffer size is reached or until the Flush or Close method is called.

In other words, the fact that all the Write operations are done doesn't mean the data is already in the MemoryStream. You have to do gzipStream.Flush() or close the gzipStream first.

Example:

using (var outStream = new MemoryStream())
{
    using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
        using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress))
        {
            fileStream.CopyTo(gzipStream);
        }

        Debug.WriteLine(
                "Compressed from {0} to {1} bytes", 
                fileStream.Length, 
                outStream.Length);

        // "outStream" is utilised here (persisted to a NoSql database).
    }
} 

Also, ideally, put it outside of the FileStream as well - you want to close files as soon as you can, rather than waiting for some other processing to finish.

Paraesthesia answered 6/12, 2013 at 12:30 Comment(5)
I suspected a lack of flushing to be the culprit at first, but the docs on GZipStream.Flush explicitly state that the "current implementation of this method has no functionality", closing the stream is indeed the only option.Tenpin
@O.R.Mapper: ILSpy seems to confirm that. Wow, that's a bit under the belt. I guess they didn't have a way to implement it, since it can't work incrementally, you probably need to have all of the data compressed and written at once.Paraesthesia
That didn't work - wrapping a using around fileStream.CopyTo() (or indeed closing gzipStream after the CopyTo, as mentioned in my question) results in outStream also closing, making it unusable in later lines.Stylographic
@AndrewStephens: Yes, that's what the third parameter of the GZipStream constructor is for - if you use new GZipStream(outStream, CompressionMode.Compress, true), it should leave the outStream open. Don't forget to rewind the MemoryStream (outStream.Position = 0;).Paraesthesia
The third parameter did the trick, thanks! Marked as answered.Stylographic

© 2022 - 2024 — McMap. All rights reserved.