Распакуйте файл данных с помощью DeflateStream - PullRequest
6 голосов
/ 07 октября 2009

У меня проблемы с чтением сжатого (дефлированного) файла данных с использованием C # .NET DeflateStream(..., CompressionMode.Decompress). Файл был написан ранее с использованием DeflateStream(..., CompressionMode.Compress), и он, кажется, просто отлично (я могу даже распаковать его с помощью программы на Java).

Однако первый Read() вызов входного потока для распаковки / раздувания сжатых данных возвращает нулевую длину (конец файла).

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

public void Main(...)
{
    Stream  inp;
    Stream  outp;
    bool    compr;  

    ...
    inp = new FileStream(inName, FileMode.Open, FileAccess.Read);
    outp = new FileStream(outName, FileMode.Create, FileAccess.Write);  

    if (compr)
        Compress(inp, outp);
    else
        Decompress(inp, outp);  

    inp.Close();
    outp.Close();
}

Вот базовый код для декомпрессии, который терпит неудачу:

public long Decompress(Stream inp, Stream outp)
{
    byte[]  buf = new byte[BUF_SIZE];
    long    nBytes = 0;  

    // Decompress the contents of the input file
    inp = new DeflateStream(inp, CompressionMode.Decompress);  

    for (;;)
    {
        int   len;  

        // Read a data block from the input stream
        len = inp.Read(buf, 0, buf.Length);    //<<FAILS
        if (len <= 0)
            break;  

        // Write the data block to the decompressed output stream
        outp.Write(buf, 0, len);
        nBytes += len;
    }  

    // Done
    outp.Flush();
    return nBytes;
}

Вызов, помеченный FAILS, всегда возвращает ноль. Зачем? Я знаю, что это должно быть что-то простое, но я просто не вижу этого.

Вот базовый код для сжатия, который прекрасно работает и практически идентичен методу распаковки с замененными именами:

public long Compress(Stream inp, Stream outp)
{
    byte[]  buf = new byte[BUF_SIZE];
    long    nBytes = 0;  

    // Compress the contents of the input file
    outp = new DeflateStream(outp, CompressionMode.Compress);  

    for (;;)
    {
        int   len;  

        // Read a data block from the input stream
        len = inp.Read(buf, 0, buf.Length);
        if (len <= 0)
            break;  

        // Write the data block to the compressed output stream
        outp.Write(buf, 0, len);
        nBytes += len;
    }  

    // Done
    outp.Flush();
    return nBytes;
}  

решаемые

После просмотра правильного решения оператор конструктора должен быть изменен на:

inp = new DeflateStream(inp, CompressionMode.Decompress, true);

, который поддерживает основной входной поток открытым, и после вызова inp.Flush() необходимо добавить следующую строку:

inp.Close();

Вызов Close() заставляет поток дефлагера очищать свои внутренние буферы. Флаг true не позволяет ему закрыть базовый поток, который закрывается позже в Main(). Те же изменения должны быть внесены и в метод Compress().

Ответы [ 2 ]

5 голосов
/ 07 октября 2009

В вашем методе распаковки переназначается inp новому потоку (потоку дефлята). Вы никогда не закрываете этот поток Deflate, но вы закрываете основной файловый поток в Main (). Аналогичная вещь происходит в методе компрессии.

Я думаю, что проблема в том, что основной файловый поток закрывается до того, как финализаторы потока deflate автоматически их закрывают.

Я добавил 1 строку кода в ваши методы распаковки и сжатия: inp.Close () // для декомпрессионного метода

outp.Close () // к методу сжатия.

лучшей практикой было бы заключать потоки в условие использования.

Вот альтернативный способ написания вашего метода распаковки (я проверял, и он работает)


    public static long Decompress(Stream inp, Stream outp)
    {
        byte[]  buf = new byte[BUF_SIZE];
        long    nBytes = 0;  

        // Decompress the contents of the input file
        using (inp = new DeflateStream(inp, CompressionMode.Decompress))
        {
            int len;
            while ((len = inp.Read(buf, 0, buf.Length)) > 0)
            {
                // Write the data block to the decompressed output stream
                outp.Write(buf, 0, len);
                nBytes += len;
            }  
        }
        // Done
        return nBytes;
    }
    
0 голосов
/ 07 октября 2009

У меня была та же проблема с GZipStream, поскольку у нас была сохранена исходная длина, мне пришлось переписать код, чтобы прочитать только количество байтов, ожидаемое в исходном файле.

Надеюсь, я собираюсь узнать, что был лучший ответ (скрестив пальцы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...