使用 DeflateStream 解压缩数据文件

发布于 2024-08-06 08:58:25 字数 2461 浏览 3 评论 0原文

我在使用 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() 方法进行相同的更改。

I'm having trouble reading a compressed (deflated) data file using C# .NET DeflateStream(..., CompressionMode.Decompress). The file was written earlier using DeflateStream(..., CompressionMode.Compress), and it seems to be just fine (I can even decompress it using a Java program).

However, the first Read() call on the input stream to decompress/inflate the compressed data returns a length of zero (end of file).

Here's the main driver, which is used for both compression and decompression:

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

Here's the basic code for decompression, which is what is failing:

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

The call marked FAILS always returns zero. Why? I know it's got to be something simple, but I'm just not seeing it.

Here's the basic code for compression, which works just fine, and is almost exactly the same as the decompression method with the names swapped:

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

Solved

After seeing the correct solution, the constructor statement should be changed to:

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

which keeps the underlying input stream open, and the following line needs to be added following the inp.Flush() call:

inp.Close();

The Close() calls forces the deflater stream to flush its internal buffers. The true flag prevents it from closing the underlying stream, which is closed later in Main(). The same changes should also be made to the Compress() method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我最亲爱的 2024-08-13 08:58:26

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

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

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

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

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

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


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

In your decompress method, are reassigning inp to a new Stream (a deflate stream). You never close that Deflate stream, but you do close the underlying file stream in Main(). A similar thing is going on in the compress method.

I think that the problem is that the underlying file stream is being closed before the deflate stream's finalizers are automatically closing them.

I added 1 line of code to your Decompress and Compress methods:
inp.Close() // to the Decompressmehtod

outp.Close() // to the compress method.

a better practice would be to enclose the streams in a using clause.

Here's an alternative way to write your Decompress method (I tested, and it works)


    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;
    }
    
爱她像谁 2024-08-13 08:58:26

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

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

I had the same problem with GZipStream, Since we had the original length stored I had to re-write the code to only read the number of bytes expected in the original file.

Hopefully I'm about to learn that there was a better answer (fingers crossed).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文