使用DeflateStream解压缩数据文件

时间:2009-10-06 22:51:06

标签: c# .net compression

我在使用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()调用强制deflater流刷新其内部缓冲区。 true标志阻止它关闭基础流,后者将在Main()中关闭。同样的变化也应该用于Compress()方法。

2 个答案:

答案 0 :(得分:5)

在您的解压缩方法中,将inp重新分配给新的Stream(deflate流)。您永远不会关闭该Deflate流,但您确实在Main()中关闭了基础文件流。压缩方法也有类似的事情发生。

我认为问题是在deflate流的终结器自动关闭之前,底层文件流正在关闭。

我在你的Decompress和Compress方法中添加了一行代码: inp.Close()//到Decompressmehtod

outp.Close()//到compress方法。

更好的做法是将流包含在using子句中。

这是编写解压缩方法的另一种方法(我测试过,它有效)


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

答案 1 :(得分:0)

我遇到了与GZipStream相同的问题,因为我们已经存储了原始长度,所以我必须重新编写代码才能读取原始文件中预期的字节数。

希望我能够知道有更好的答案(手指交叉)。