【问题标题】:Opening and Reading from a "large" gzip compressed file in C在 C 中打开和读取“大”gzip 压缩文件
【发布时间】:2017-11-23 07:19:40
【问题描述】:

我一直在尝试使用 C 中 gzip-based 文件 IO 函数打开和读取 gzip 压缩文件。我随身携带的压缩文件非常大大小为 12 GB。未压缩的文件是 ~260 GB,因此我不准备使用 gunzip 解压缩文件并从那里继续。

我专门使用下面的代码来读取和写入我们可用的缓冲区-

#define windowBits 15
#define ENABLE_ZLIB_GZIP 32

#define CHUNK 0x4000

#define CALL_ZLIB(x) {  \
    int status;     \
    status = x;     \
    if (status < 0) \
    {               \
            fprintf(stderr, "%s:%d: %s returned a bad status of %d.\n", __FILE__, __LINE__, #x, status);  \
            exit(EXIT_FAILURE);\
    }              \
 }                 \



int main ()
{
    const char * file_name = "test.gz";
    FILE * file;
    z_stream strm = {0};
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.next_in = in;
    strm.avail_in = 0;
    CALL_ZLIB (inflateInit2 (& strm, windowBits | ENABLE_ZLIB_GZIP));

    /* Open the file. */

    file = fopen (file_name, "rb");

    while (1) {
        int bytes_read;

        bytes_read = fread (in, sizeof (char), sizeof (in), file);

        strm.avail_in = bytes_read;
        do {
            unsigned have;
            strm.avail_out = CHUNK;
            strm.next_out = out;
            CALL_ZLIB (inflate (& strm, Z_NO_FLUSH));
            have = CHUNK - strm.avail_out;
            fwrite (out, sizeof (unsigned char), have, stdout);
        }
        while (strm.avail_out == 0);
        if (feof (file)) {
            inflateEnd (& strm);
            break;
        }
    }

    return 0;
}

代码根据您最初指定的缓冲区准确地读取和写入 zlib 文件。缓冲区大小被固定为某个值(在上述情况下为 0x4000)。

现在的问题是我无法将此缓冲区的大小增加到某个值以上(我可以使用 3276008 作为缓冲区大小,但不能使用 32760008)。要读取 12 GB 的压缩值,我需要使用非常大的缓冲区。正如我在编辑中指定的那样,这看起来像是某种DATA_ERROR 而不是BUFFERerror...所以它毕竟不是缓冲区错误!

有什么方法可以使用上面的zlib 函数记录整个 12 GB 压缩文件?

编辑#1

函数inflate返回的错误码是由CALL_ZLIB函数封装的,很抱歉没有包括在内。因此,当我以 0x4000 的缓冲区大小运行时,我得到以下错误代码。我已经在代码中添加了 CALL_ZLIB 函数供您参考。

错误信息:

parser.c:96: inflate(&amp;strm, Z_NO_FLUSH) returned a bad status of -3。这显然看起来像一个**DATA_ERROR。

编辑#2

我尝试将 windowBits 的负值 添加到 InflateInit2() ,但这并没有解决我的任何问题。 inflate() 函数最初会正确读取我的文件——以我想要的方式显示我的所有数据..

0x55b0 [0x40]: event: 3
.
. ... raw event: size 64 bytes
.  0000:  03 00 00 00 00 00 40 00 18 03 00 00 18 03 00 00  ......@.........
.  0010:  4d 6f 64 65 6d 4d 61 6e 61 67 65 72 00 00 00 00  ModemManager....
.  0020:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
.  0030:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

0 0 0x55b0 [0x40]: PERF_RECORD_COMM: ModemManager:792/792

0x55f0 [0x40]: event: 7
.
. ... raw event: size 64 bytes
.  0000:  07 00 00 00 00 00 40 00 19 03 00 00 01 00 00 00  ......@.........
.  0010:  19 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00  ................
.  0020:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
.  0030:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

0 0 0x55f0 [0x40]: PERF_RECORD_FORK(793:793):(1:1)

0x5630 [0x40]: event: 3
.

但是一段时间后,显示的输出变得乱码,我无法再读取它了..

0x4d68 [0x38]: ...........  001  0..
0 0 00 00 00 0 00 000 00 ze 64s
.  0000:  07 00 00 00 00 00 40 00 19 03 00 00 01 00 00 00  .. 00 0 event: size 64 bytes
.  0000:  03 00 00 00  si sisizsiz4s
.  0000:  07 00 00 00 00 00 40 00 19 0....
.  0030:  00 00 00 00 00 00 00 00 00 00 00 00 ..@.@.  0010:  19 03 00 00 [0x38]: ...........  001  0..
0 0 00 00 00 0 00 000 00 ze 64s
.  0000:  07 00 00 00 00 00 40 00 100 00 00 00 00  ..............0 0 0x4d28 [0x40]: PERF_RECORD_FORK(135:135):(2:62)

0x4d68 [0x38]: ...........  001  0..
0 0 00 00 00 0 00 000 00 00 00 00: PERORD_FORK(135:135):(2:2)

这最终以我在编辑 #1 中描述的错误消息终止

【问题讨论】:

  • system("/bin/gunzip mybigfile.gz");?或fork() exec() ...
  • gunzip 将返回 260 GB 的原始文件 - 我不打算使用这个大文件.. 这就是我压缩它的原因。我实际上想轻松读取和解析这个文件..
  • zlib 系统获取文件的一小块,并解压缩它。此输出正在填充您的输出缓冲区。您是否尝试使用 260Mb 的 IO 来“处理”数据?窗口大小和缓冲区,不影响zlib可以处理的数据量
  • 我已经有一个 .gz 文件。我试图直接从该文件中读取,而不是解压缩它,因为原始文件是 260 GB,我设法将它减少到 12 GB(这是我的 .gz 文件)。一旦我增加缓冲区,我可以看到程序在出现段错误之前读取比以前更多的数据。但看起来缓冲区有限制。

标签: c file io gzip


【解决方案1】:

我已经解决了这个问题。

基本问题是我没有在循环内的代码中初始化 z_stream 的 strm.next_in 成员。因此,在进行 1 次迭代后,缓冲区已损坏,并且出现上述错误。

我将代码修改为 --

  strm.next_in = in;
  strm.avail_in = 0;

  CALL_ZLIB(inflateInit2 (&strm, windowBits | ENABLE_ZLIB_GZIP));

  file = fopen(filename, "rb");

  while(1)
  {
    int bytes_read;
    strm.next_in = in;     // added this line

    bytes_read = fread(in, sizeof(char), sizeof(in), file);

    strm.avail_in = bytes_read;

    do
    {
      unsigned have;
      strm.avail_out = CHUNK;
      strm.next_out  = out;

【讨论】:

    猜你喜欢
    • 2010-10-12
    • 2016-06-25
    • 2013-12-23
    • 2014-07-04
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多