GZipStream и распаковка

У меня есть код, который должен выполнять сжатие:

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();

и я думаю, что это так, но я хочу распаковать то, что было сжато выше. Я делаю что-то вроде этого:

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();

а здесь нет... У меня nRead = 0 перед входом в цикл... Что я делаю не так?? Тестовый файл, который я использую, представляет собой простейший текстовый файл (размер: 104 байта)...


person Community    schedule 17.10.2009    source источник
comment
Отредактированный ответ, чтобы показать как чтение, так и запись   -  person Marc Gravell    schedule 17.10.2009
comment
Обратите внимание, что gzip != .zip   -  person Marc Gravell    schedule 17.10.2009
comment
(обратите внимание, я исправил ошибку после публикации; проверьте, что обе петли while только Read в верхней строке (а не в нижней).   -  person Marc Gravell    schedule 17.10.2009


Ответы (2)


Моя первая мысль, что вы не закрыли csStream. Если вы используете using, это происходит автоматически. Поскольку gzip буферизует данные, некоторые из них могут быть упущены.

Во-вторых; не увеличивать offset; это смещение в буфере (не в потоке). Оставить на 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);
    }
}
person Marc Gravell    schedule 17.10.2009
comment
Проблема в том, что сжатие работает хорошо, а распаковать не получается. - person ; 17.10.2009
comment
Вместо буферного цикла вы также можете использовать встроенную функцию .CopyTo(). В этом случае это будет: csStream.CopyTo(fd); - person James Roland; 04.01.2011
comment
@JamesR - не когда этот ответ был написан, я не мог ;p - person Marc Gravell; 04.01.2011
comment
Хороший вопрос, просто добавляю к этому немного знаний. Еще одна раздражающая вещь, которую я обнаружил с GZipStream. Если вы пишете в MemoryStream, вам нужно .Close() для GZipStream. В противном случае он будет удерживать последние несколько байтов. .Flush(), похоже, не выполняет эту работу. (Это если вы используете MemoryStream внутри оператора using.) - person James Roland; 04.01.2011
comment
@James действительно, но это побочный эффект самого GZIP; и, по крайней мере, вы получаете возможность (в конструкторе), чтобы это не закрывало базовый поток. Это влияет на все направления, кстати, а не только на MemoryStream. - person Marc Gravell; 04.01.2011

У меня есть два метода, как упомянул Джеймс Роланд.

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();
}

Однако я использую загрузку с

Request.Files[0] 

затем сжать и сохранить в БД. Затем я вытаскиваю img, распаковываю и устанавливаю src с помощью

$"data:image/gif;base64,{ToBase64String(Decompress(img))}";
person Stephen Himes    schedule 25.01.2018
comment
Никогда не используйте объект IDisposable без using! - person JCKödel; 08.03.2018
comment
@JCKödel Хотя он явно предпочитал использовать using, когда это было возможно, говорить «никогда» просто неточно, и существует множество обстоятельств, когда это нежелательно и / или возможно. - person ForeverZer0; 22.08.2018
comment
если вы не используете IDisposable и не используете синтаксис, то рекомендуется использовать try/catch/finally и не передавать поток от функции к функции (если вы можете этого избежать). - person Roman; 10.03.2020