適切で完全な「圧縮ストリーム」を提供していて、データを出力するのに十分なスペースがあると仮定するとinflate、呼び出す必要があるのはinflate1 回だけです。
編集: zlib documentationほど明確に書かれていませんが、次のように述べています:
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
Bz_stream : というオブジェクトを設定しますstrm。これはさまざまなフィールドを保持しますが、そのほとんどはここでは重要ではありません (したがって、Z_NULL に設定されます)。重要なものはavail_inandnext_inとavail_outandnext_outです (これらは後で設定されます)。
C : 膨張プロセスを開始します。これにより、いくつかの内部データ構造がセットアップされ、inflate関数自体が「実行可能」になります。
D : ファイルから「CHUNK」量のデータを読み取ります。読み取ったバイト数を に格納するstrm.avail_inと、実際のデータが に入りinます。
E : エラーが発生した場合は、inflateを呼び出して終了しinflateEndます。ジョブ完了。
F : データがありません。
G : データの送信元を設定します (next_inは入力バッファに設定されますin)。
H : 私たちは今、物事を膨らませるループに入っています。ここでは、出力バッファを設定しますnext_out。avail_out出力がどこに行き、どれだけのスペースがあるかをそれぞれ示します。
I : 自分自身を呼び出しinflateます。これにより、出力がいっぱいになるまで、入力バッファーの一部が圧縮解除されます。
J : このステップで使用できるデータの量を計算します (haveはバイト数)。
K : 終了時にスペースが残るまで- これは、出力バッファーのスペースが不足するのではなくinflate、バッファー内のデータの出力が完了したことを示します。inそれでは、入力ファイルからさらにデータを読み取ります。
L : 呼び出しのエラー コードinflateが「happy」の場合は、もう一度ラウンドします。
明らかに、ネットワークから読み取り、メモリに圧縮解除する場合は、freadandfwriteを適切なread from networkand memcpytype 呼び出しに置き換える必要があります。あなたのデータがどこから来たのかを説明するものを何も提供していないので、それらが何であるかを正確に伝えることはできません -recvまたはreadまたはWSARecv、または何か他のものを呼び出していますか? -そして、それはどこへ行くのですか?