C# 使用DeflateStream解压数据文件

C# 使用DeflateStream解压数据文件,c#,.net,compression,C#,.net,Compression,使用C#.NETDeflateStream(…,CompressionMode.Decompress)读取压缩(放气)数据文件时遇到问题。。该文件是在前面使用DeflateStream(…,CompressionMode.Compress)编写的,看起来还不错(我甚至可以使用Java程序对其进行解压缩) 但是,对输入流进行第一次Read()调用以解压缩/膨胀压缩数据时,返回的长度为零(文件结束) 以下是用于压缩和解压缩的主要驱动程序: public void Main(...) { St

使用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;
}
解决

在看到正确的解决方案后,构造函数语句应更改为:

inp = new DeflateStream(inp, CompressionMode.Decompress, true);
它保持基础输入流打开,需要在
inp.Flush()
调用之后添加以下行:

inp.Close();

Close()
调用强制放气流刷新其内部缓冲区。
true
标志阻止它关闭底层流,该流稍后在
Main()
中关闭。对
Compress()
方法也应该做同样的更改。

我对GZipStream也有同样的问题,因为我们存储了原始长度,所以我必须重新编写代码,以便只读取原始文件中预期的字节数


希望我即将了解到有一个更好的答案(祈祷)。

在您的解压缩方法中,正在将inp重新分配给一个新流(放气流)。您永远不会关闭该Deflate流,但会在Main()中关闭底层文件流。在压缩方法中也发生了类似的事情

我认为问题在于底层文件流在deflate流的终结器自动关闭它们之前被关闭

我在解压和压缩方法中添加了1行代码: inp.Close()//到解压缩方法

outp.Close()//到compress方法

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

这里有一种编写解压方法的替代方法(我测试过,它可以工作)


@顺便说一句:当我运行你的代码时,我没有得到与你描述的相同的行为,但它也不起作用。在我的例子中,解压缩似乎是成功的,但是如果我将解压缩的文件与原始文件进行比较,它们不匹配。解压缩的文件比原始文件小--缺少字节。对DeflateStream调用close()的更改也解决了这个问题。我怀疑行为上的差异可能只是与我的测试文件和你的测试文件的大小有关——可能它删除了最后N个字节,而我的文件更大(我的是364391个字节)。Doh。当然,它在文档中说,您必须关闭deflater流,以确保正确刷新所有内部缓冲区。我应该在
Decompress()
Compress()
方法中对压缩器/解压缩器流调用
Close()
,因为它们直接控制压缩器/解压缩器流。或者,我可以使用
keepOpen
标志true打开
DeflaterStream
,以保持底层输入流打开。我仍然会关闭deflater流,但之后我也会关闭底层文件流。我试过这个,效果很好。
inp.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;
    }