使用 DeflateStream 解压缩数据文件
我在使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在您的解压缩方法中,将 inp 重新分配给新的 Stream(一个 deflate 流)。您永远不会关闭 Deflate 流,但您确实会在 Main() 中关闭底层文件流。 compress 方法中也发生了类似的事情。
我认为问题在于底层文件流在 deflate 流的终结器自动关闭它们之前被关闭。
我在解压缩和压缩方法中添加了 1 行代码:
inp.Close() // 到 Decompressmehtod
outp.Close() // 到 compress 方法。
更好的做法是将流包含在 using 子句中。
这是编写 Decompress 方法的另一种方法(我测试过,它有效)
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)
我对 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).