假设您提供inflate
了一个适当且完整的“压缩流”,并且有足够的空间来输出数据,您只需要调用inflate
一次。
编辑:它没有像zlib 文档中那样清楚地写出来,但它确实说:
inflate
解压缩尽可能多的数据,并在输入缓冲区变空或输出缓冲区变满时停止。除非强制刷新,否则它可能会引入一些输出延迟(读取输入而不产生任何输出)。
当然,对于任何尚未“在内存中并完成”的流,您希望逐块运行它,因为这将减少总运行时间(您可以在接收数据时解压缩 [来自网络或文件系统下一个块的预取缓存]。
这是您的示例代码中的整个函数。我已经从页面中删除了文本组件以集中代码,并用字母等标记部分// A
,// B
然后标记试图解释下面的部分。
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK]; // A
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL; // B
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm); // C
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source); // D
if (ferror(source)) {
(void)inflateEnd(&strm); // E
return Z_ERRNO;
}
if (strm.avail_in == 0) // F
break;
strm.next_in = in; // G
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK; // H
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH); // I
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
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; // J
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0); // K
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END); // L
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
A :in
是输入缓冲区(我们从文件中读取到这个缓冲区,然后将其传递给inflate
一段时间。out
是输出缓冲区,用于inflate
存储输出数据。
B:建立一个z_stream
名为 的对象strm
。这包含各种字段,其中大部分在这里并不重要(因此设置为 Z_NULL)。重要的是avail_in
andnext_in
以及avail_out
and next_out
(稍后设置)。
C : 开始充气过程。这设置了一些内部数据结构,只是使inflate
函数本身“准备好运行”。
D:从文件中读取“CHUNK”数量的数据。存储读入的字节数,strm.avail_in
实际数据进入in
。
E : 如果我们出错了,inflate
通过调用来完成inflateEnd
。任务完成。
F : 没有可用的数据,我们结束了。
G:设置我们的数据来自哪里(next_in
设置为输入缓冲区,in
)。
H : 我们现在正处于膨胀的循环中。在这里,我们设置了输出缓冲区:next_out
并avail_out
分别指示输出到哪里以及有多少空间。
我:调用inflate
它自己。这将解压缩输入缓冲区的一部分,直到输出已满。
J:计算这一步有多少数据可用(have
是字节数)。
K : 直到inflate
完成时有剩余空间 - 这表示缓冲区中的数据的输出已完成in
,而不是输出缓冲区中的空间不足。所以是时候从输入文件中读取更多数据了。
L:如果inflate
调用的错误代码是“happy”,请再转一圈。
现在,显然,如果您正在从网络读取数据并解压缩到内存中,则需要将fread
and替换为fwrite
一些合适的read from network
和memcpy
type 调用。我不能确切地告诉你这些是什么,因为你没有提供任何东西来解释你的数据来自哪里——你是打电话给recv
orread
还是WSARecv
别的什么?- 它要去哪里?