Запись в поток сжатия не поддерживается. Использование System.IO.GZipStream

Я получаю исключение при попытке распаковать файл (.gz) с помощью класса GZipStream, включенного в платформу .NET. Я использую документацию MSDN. Это исключение:

Запись в поток сжатия не поддерживается.

Вот исходник приложения:

 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 {...}

Исключение вызывается сжатымZipStream.write().

Есть идеи? Что мне говорит это исключение?


person Nick    schedule 30.08.2009    source источник


Ответы (3)


Он говорит вам, что вы должны вызывать Read вместо Write, так как это декомпрессия! Также поток памяти должен быть создан с данными, или, скорее, вы должны передать файловый поток непосредственно конструктору GZipStream.

Пример того, как это должно было быть сделано (не пробовал компилировать):

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
person Filip Navara    schedule 30.08.2009

Код сжатия работает не так, как шифрование — вы не можете выполнять распаковку из одного потока в другой, записывая сжатые данные. Вы должны предоставить поток, который уже содержит сжатые данные, и позволить GZipStream прочитать его. Что-то вроде этого:

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 — это простой служебный метод для чтения из одного потока и копирования всех данных в другой. Что-то вроде этого:

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);
    }
}
person Jon Skeet    schedule 30.08.2009

То, как работают потоки сжатия, поначалу может вызывать недоумение.

Для чтения используются сжатые данные, а для записи — несжатые данные. В общем, поток гарантирует, что вы всегда «видите» только несжатые данные.

Правильный способ добиться того, что вы пытаетесь сделать, - это прочитать, используя GZipStream, а затем также написать, используя GZipStream.

person Bryan Menard    schedule 30.08.2009