我正在开发一些代码,需要能够解压缩大型 gzip 文件(未压缩的最大 5GB)并将它们读入内存。我宁愿对此保持清醒,而不是简单地将它们临时解压缩到磁盘,所以我一直在使用 zlib 来尝试实现这一点。我已经让它运行了,大部分时间。这意味着它运行我用作输入的 5 个文件中的 4 个。另一个文件在处理过程中给出了 Z_BUF_ERROR,我不想忽略它。
这最初发生在不同的代码中,但最终我将它一直带回到我从 zlib 网页上的 zpipe.c 获得的示例代码,无论我使用什么代码,它都会导致相同的 Z_BUF_ERROR 和只有这个文件。在阅读了关于 Z_BUF_ERROR 的几篇文章以及关于此的手册之后,我玩了很长时间代码。最终,我找到了一种方法,通过更改用于保存膨胀输出的缓冲区的大小来使其工作。通常在这一点上,我会称之为一天,直到它报告另一个文件的错误,但理想情况下,这将是某个时候的生产级代码,我想了解错误是什么,所以我可以防止它,而不仅仅是暂时修复它。特别是因为 gzip 能够很好地压缩和解压缩文件。
我尝试了以下变体:
- 不同平台:CentOS、OSX
- zlib 的不同版本:1.2.3、1.2.8(结果相同)
- CHUNK 的值和输出的字节数(完整的是 783049330):
- 2000000: 783049330
- 1048576: 783049330
- 1000000: 783049330
- 100000: 783049330
- 30000: 248421347
- 25000: 31095404
- 20000: 783049330
- 19000: 155821787
- 18000: 412613687
- 17000: 55799133
- 16384: 37541674
- 16000: 783049330
- 任何大于 4100000 的 CHUNK 大小都会出错
- 尝试声明一个大于 CHUNK 的值(相同的结果)
- 尝试使用 malloc 声明 out(相同结果)
- 尝试使用 gzip 解压缩然后再次压缩文件,认为 gzip 元数据中可能存在某些问题(相同结果)
- 尝试使用 gzip 压缩文件的单独未压缩版本以达到相同目的,但我相信原始 .gz 文件是从这个文件创建的(相同结果)
我可能已经尝试了这个列表之外的一些东西,因为我一直试图深入了解它一段时间,但只有更改 CHUNK 大小才能完成这项工作。我唯一担心的是,我不知道为什么不同的大小会起作用,而且我担心另一个 CHUNK 大小会使其他文件面临此问题的风险,因为同样,这只是一个文件的问题。
` 代码:
FILE* fp = fopen( argv[1], "rb" );
int ret = inf( fp, stdout );
fclose( fp );
int inf(FILE *source, FILE *dest)
{
size_t CHUNK = 100000;
int count = 0;
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
char out_str[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit2(&strm, 16+MAX_WBITS);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source);
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
char out_str[have+1];
strncpy( out_str, (char*)out, have );
out_str[have] = '\0';
// testing the ability to store the result in a string object and viewing the output
std::cout << "out_str: " << std::string(out_str) << " ::" << std::endl;
if( ret == Z_BUF_ERROR ){
std::cout << "Z_BUF_ERROR!" << std::endl;
exit(1);
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
`
最佳答案
你应该阅读评论where you got that code from . Z_BUF_ERROR
只是表明 inflate()
对该调用无能为力。只需继续并为下一个 inflate()
调用提供更多输入数据和更多输出空间。
关于c++ - 具有特定文件和特定缓冲区大小的 zlib Z_BUF_ERROR,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26482218/