Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing to the compression stream is not supported. Using System.IO.GZipStream

I get an exception when trying to decompress a (.gz) file using the GZipStream class that is included in the .NET framework. I am using the MSDN documentation. This is the exception:

Writing to the compression stream is not supported.

Here is the application source:

 try
 {
     var infile = new FileStream(@"C:\TarDecomp\TarDecomp\TarDecomp\bin\Debug\nick_blah-2008.tar.gz", FileMode.Open, FileAccess.Read, FileShare.Read);
     byte[] buffer = new byte[infile.Length];
     // Read the file to ensure it is readable.
     int count = infile.Read(buffer, 0, buffer.Length);
     if (count != buffer.Length)
     {
         infile.Close();
         Console.WriteLine("Test Failed: Unable to read data from file");
         return;
     }
     infile.Close();
     MemoryStream ms = new MemoryStream();
     // Use the newly created memory stream for the compressed data.
     GZipStream compressedzipStream = new GZipStream(ms, CompressionMode.Decompress, true);
     Console.WriteLine("Decompression");
     compressedzipStream.Write(buffer, 0, buffer.Length); //<<Throws error here
     // Close the stream.
     compressedzipStream.Close();
     Console.WriteLine("Original size: {0}, Compressed size: {1}", buffer.Length, ms.Length);
} catch {...}

The exception is thrown at the compressedZipStream.write().

Any ideas? What is this exception telling me?

like image 330
Nick Avatar asked Aug 30 '09 19:08

Nick


3 Answers

It is telling you that you should call Read instead of Write since it's decompression! Also the memory stream should be constructed with the data, or rather you should pass the file stream directly to the GZipStream constructor.

Example of how it should have been done (haven't tried to compile it):

Stream inFile = new FileStream(@"C:\TarDecomp\TarDecomp\TarDecomp\bin\Debug\nick_blah-2008.tar.gz", FileMode.Open, FileAccess.Read, FileShare.Read);
Stream decodedStream = new MemoryStream();
byte[] buffer = new byte[4096];

using (Stream inGzipStream = new GZipStream(inFile, CompressionMode.Decompress))
{
    int bytesRead;
    while ((bytesRead = inGzipStream.Read(buffer, 0, buffer.Length)) > 0)
        decodedStream.Write(buffer, 0, bytesRead);
}

// Now decodedStream contains the decoded data
like image 101
Filip Navara Avatar answered Oct 16 '22 09:10

Filip Navara


The compression code doesn't work like encryption - you can't decompress from one stream to another by writing the compressed data. You have to provide a stream which contains the compressed data already and let GZipStream read from it. Something like this:

using (Stream file = File.OpenRead(filename))
using (Stream gzip = new GZipStream(file, CompressionMode.Decompress))
using (Stream memoryStream = new MemoryStream())
{
   CopyStream(gzip, memoryStream);
   return memoryStream.ToArray();
}

CopyStream is a simple utility method to read from one stream and copy all the data to another. Something like this:

static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}
like image 30
Jon Skeet Avatar answered Oct 16 '22 10:10

Jon Skeet


How compression streams work can be puzzling at first.

Reading takes compressed data and writing takes uncompressed data. All in all, the stream ensures you only "see" uncompressed data at all times.

The proper way to achieve what you are trying to do, is to read using the GZipStream and then write using the GZipStream also.

like image 41
Bryan Menard Avatar answered Oct 16 '22 08:10

Bryan Menard