zlib Z_BUF_ERROR具有特定文件和特定缓冲区大小

时间:2014-10-21 08:32:27

标签: c++ zlib

我正在开发一些代码,这些代码需要能够解压缩大型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声明(相同的结果)
  • 尝试使用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;
}

`

1 个答案:

答案 0 :(得分:2)

你应该阅读评论where you got that code fromZ_BUF_ERROR只表示inflate()没有任何内容可以通过该电话进行操作。只需继续并为下一次inflate()呼叫提供更多输入数据和更多输出空间。