GZipStream and decompression
Asked Answered
G

2

17

I have code that should do the compression:

FileStream fs = new FileStream("g:\\gj.txt", FileMode.Open);
FileStream fd = new FileStream("g:\\gj.zip", FileMode.Create);
GZipStream csStream = new GZipStream(fd, CompressionMode.Compress);

byte[] compressedBuffer = new byte[500];
int offset = 0;
int nRead;

nRead = fs.Read(compressedBuffer, offset, compressedBuffer.Length);
while (nRead > 0)
{
    csStream.Write(compressedBuffer, offset, nRead);
    offset = offset + nRead;
    nRead = fs.Read(compressedBuffer, offset, compressedBuffer.Length);
}

fd.Close();
fs.Close();

and I think it does, but I want to decompress what was compressed the way above. I do somethink like that:

FileStream fd = new FileStream("g:\\gj.new", FileMode.Create);
FileStream fs = new FileStream("g:\\gj.zip", FileMode.Open);
GZipStream csStream = new GZipStream(fs, CompressionMode.Decompress);

byte[] decompressedBuffer = new byte[500];
int offset = 0;
int nRead;

nRead=csStream.Read(decompressedBuffer, offset, decompressedBuffer.Length);
while (nRead > 0)
{
    fd.Write(decompressedBuffer, offset, nRead);
    offset = offset + nRead;
    nRead = csStream.Read(decompressedBuffer, offset, decompressedBuffer.Length);
}

fd.Close();
fs.Close();

and here it doesn't... I've got nRead = 0 befeore entering the loop... What I do wrong?? The test file I use is the simpliest TEXT file (size: 104 bytes)...

Geter answered 17/10, 2009 at 7:58 Comment(3)
Edited answer to show both read and writeMccready
Note also that gzip != ".zip"Mccready
(note I fixed a bug after posting; cheack that both while loops only Read on the top line (not at the bottom as well).Mccready
M
24

My first thought is that you haven't closed csStream. If you use using this happens automatically. Since gzip buffers data, you could be missing some.

Secondly; don't increment offset; that is the offset in the buffer (not the stream). Leave at 0:

using (Stream fs = File.OpenRead("gj.txt"))
using (Stream fd = File.Create("gj.zip"))
using (Stream csStream = new GZipStream(fd, CompressionMode.Compress))
{
    byte[] buffer = new byte[1024];
    int nRead;
    while ((nRead = fs.Read(buffer, 0, buffer.Length))> 0)
    {
        csStream.Write(buffer, 0, nRead);
    }
}

using (Stream fd = File.Create("gj.new.txt"))
using (Stream fs = File.OpenRead("gj.zip"))
using (Stream csStream = new GZipStream(fs, CompressionMode.Decompress))
{
    byte[] buffer = new byte[1024];
    int nRead;
    while ((nRead = csStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        fd.Write(buffer, 0, nRead);
    }
}
Mccready answered 17/10, 2009 at 8:7 Comment(5)
The problem is that commression works well, but cant make it to decompress.Geter
Instead of the buffer loop you can also use the built in .CopyTo() function. In this case it would be: csStream.CopyTo(fd);Mccall
@JamesR - not when this answer was written, I couldn't ;pMccready
Good point, just adding to this bit of knowledge. One other annoying thing I found with GZipStream. If you are writing to a MemoryStream you have to .Close() the GZipStream. Otherwise it will hold on to the last few bytes. .Flush() does not seem to do the job. (This is if you use the MemoryStream inside the using statement.)Mccall
@James indeed, but that is a side effect of GZIP itself; and at least you get the option (in the constructor) to have this not close the underlying stream. It affects all destinations, btw - not just MemoryStream.Mccready
D
12

The two methods I have are like James Roland mentioned.

private static byte[] Compress(HttpPostedFileBase file)
{
    using var to = new MemoryStream();
    using var gZipStream = new GZipStream(to, CompressionMode.Compress);
    file.InputStream.CopyTo(gZipStream);
    gZipStream.Flush();
    return to.ToArray();
}

private static byte[] Decompress(byte[] compressed)
{
    using var from = new MemoryStream(compressed);
    using var to = new MemoryStream();
    using var gZipStream = new GZipStream(from, CompressionMode.Decompress);
    gZipStream.CopyTo(to);
    return to.ToArray();
}

However, I'm using an upload with

Request.Files[0] 

then compress and save in the db. Then I pull the img out, decompress and set a src with

$"data:image/gif;base64,{ToBase64String(Decompress(img))}";
Dollop answered 25/1, 2018 at 11:4 Comment(3)
Never use an IDisposable object without using!Centistere
@JCKödel Although it obviously preferred to take advantage of using when possible, saying "never" is just not accurate, and there are plenty of circumstances where it is not desired and/or possible.Gyp
if you're not taking advantage of IDisposable and using syntax, then recommendation is to ensure using try/catch/finally and do not pass the stream from function to function (if you can avoid it).Laryssa

© 2022 - 2024 — McMap. All rights reserved.