【发布时间】: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(&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 文件)。一旦我增加缓冲区,我可以看到程序在出现段错误之前读取比以前更多的数据。但看起来缓冲区有限制。