Yes Man
Yes Man

Reputation: 411

Original file bigger than GZip decompressed file

So I'm trying to compress an array of bytes (via a Stream). ExtendedStream is just a class I made that interfaces with a base stream (by default MemoryStream). If I take my original data, compress it, decompress it, then compare the size of the decompressed data to the size of the original data (before compression) it turns out that it's smaller than the original.

Original length: 51695, Compressed length: 26014, Decompressed length: 48685.

I'm storing tiles (7 bytes). Compressing using the GZip classes provided in the System.IO.Compression namespace.

    public static ExtendedStream GZipDecompress(ExtendedStream stream)
    {
        ExtendedStream outStream = new ExtendedStream();
        GZipStream decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, true);
        int b = -1;

        while ((b = decompressStream.ReadByte()) != -1)
        {
            outStream.WriteByte((Byte)b);
        }

        outStream.Seek(0, SeekOrigin.Begin);
        return outStream;
    }

    public static ExtendedStream GZipCompress(ExtendedStream stream)
    {
        ExtendedStream outStream = new ExtendedStream(); // base stream is a memorystream
        GZipStream compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, true);
        compressStream.Write(stream.ToArray(), 0, (int)stream.Length);
        compressStream.Flush();
        outStream.Seek(0, SeekOrigin.Begin);
        return outStream;
    }

Hope that's enough information.

Upvotes: 2

Views: 1306

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062780

You must close a compression stream; it can't write all the data until you do, due to block issues:

public static ExtendedStream GZipCompress(ExtendedStream stream)
{
    ExtendedStream outStream = new ExtendedStream();
    using(var compressStream = new GZipStream(outStream.BaseStream, CompressionMode.Compress, false)) {
        compressStream.Write(stream.GetBuffer(), 0, (int)stream.Length);
    }
    outStream.Seek(0, SeekOrigin.Begin);
    return outStream;
}

Note: normally I'd use CopyTo (or manual looping) to do the write, but since this is memory-based GetBuffer() is cheaper.

Your decompression can be simply:

decompressStream.WriteTo(outStream);

Throught both parts of this, the biggest problem (that has bitten you here) is not disposing your disposable objects. You must do this; it is a requirement of the API. To avoid prematurely disposing the outer-stream, pass "false" to the GZipStream constructor. For example:

using(var decompressStream = new GZipStream(stream.BaseStream, CompressionMode.Decompress, false)) {
    decompressionStream.CopyTo(outStream);
}

Upvotes: 2

Related Questions