概要
libbzip2
ライブラリ で低レベルの呼び出しを使用しています:BZ2_bzCompressInit()
とBZ2_bzCompress()
、BZ2_bzCompressEnd()
データのチャンクを標準出力に圧縮します。
バイトのストリームが入ってきて、それらのバイトを個別のチャンクのセットに圧縮したいので、高レベルの呼び出しから作業コードを移行しています(個別のチャンクは、対象のトークンのグループを含むバイトのセットです —私の入力は論理的にこれらのチャンクのグループに分割されます)。
チャンクの完全なグループには、たとえば 500 個のチャンクが含まれている可能性があり、これを 1 つの bzip2 ストリームに圧縮して標準出力に書き込みたいと考えています。
セット内で、以下に概説する疑似コードを使用して、サンプル バッファーが一度に 101 個のチャンクを保持できる場合、新しいストリームを開き、101、101、101、101 の実行で 500 個のチャンクを圧縮し、最後に 1 回実行します。ストリームを閉じる 96 個のチャンク。
問題
問題はbz_stream
、ルーチンの 1 回のパスで圧縮されたバイト数を追跡する構造体インスタンスがBZ2_bzCompress()
、最終的な圧縮ファイルの合計バイト数よりも多くの圧縮バイト数を書き込んでいると主張しているように見えることです。
たとえば、圧縮された出力は、実際のサイズが 1234 バイトのファイルである可能性がありますが、報告された圧縮バイト数 (デバッグ中に追跡します) は 1234 バイト (たとえば 2345 バイト) よりも若干多くなります。
私のラフな疑似コードは 2 つの部分に分かれています。
最初の部分は、チャンクのサブセットを圧縮するために私が行うことの大まかなスケッチです (そして、この後に別のサブセットがあることを知っています):
bz_stream bzStream;
unsigned char bzBuffer[BZIP2_BUFFER_MAX_LENGTH] = {0};
unsigned long bzBytesWritten = 0UL;
unsigned long long cumulativeBytesWritten = 0ULL;
unsigned char myBuffer[UNCOMPRESSED_MAX_LENGTH] = {0};
size_t myBufferLength = 0;
/* initialize bzStream */
bzStream.next_in = NULL;
bzStream.avail_in = 0U;
bzStream.avail_out = 0U;
bzStream.bzalloc = NULL;
bzStream.bzfree = NULL;
bzStream.opaque = NULL;
int bzError = BZ2_bzCompressInit(&bzStream, 9, 0, 0);
/* bzError checking... */
do
{
/* read some bytes into myBuffer... */
/* compress bytes in myBuffer */
bzStream.next_in = myBuffer;
bzStream.avail_in = myBufferLength;
bzStream.next_out = bzBuffer;
bzStream.avail_out = BZIP2_BUFFER_MAX_LENGTH;
do
{
bzStream.next_out = bzBuffer;
bzStream.avail_out = BZIP2_BUFFER_MAX_LENGTH;
bzError = BZ2_bzCompress(&bzStream, BZ_RUN);
/* error checking... */
bzBytesWritten = ((unsigned long) bzStream.total_out_hi32 << 32) + bzStream.total_out_lo32;
cumulativeBytesWritten += bzBytesWritten;
/* write compressed data in bzBuffer to standard output */
fwrite(bzBuffer, 1, bzBytesWritten, stdout);
fflush(stdout);
}
while (bzError == BZ_OK);
}
while (/* while there is a non-final myBuffer full of discrete chunks left to compress... */);
出力をまとめます。
/* read in the final batch of bytes into myBuffer (with a total byte size of `myBufferLength`... */
/* compress remaining myBufferLength bytes in myBuffer */
bzStream.next_in = myBuffer;
bzStream.avail_in = myBufferLength;
bzStream.next_out = bzBuffer;
bzStream.avail_out = BZIP2_BUFFER_MAX_LENGTH;
do
{
bzStream.next_out = bzBuffer;
bzStream.avail_out = BZIP2_BUFFER_MAX_LENGTH;
bzError = BZ2_bzCompress(&bzStream, (bzStream.avail_in) ? BZ_RUN : BZ_FINISH);
/* bzError error checking... */
/* increment cumulativeBytesWritten by `bz_stream` struct `total_out_*` members */
bzBytesWritten = ((unsigned long) bzStream.total_out_hi32 << 32) + bzStream.total_out_lo32;
cumulativeBytesWritten += bzBytesWritten;
/* write compressed data in bzBuffer to standard output */
fwrite(bzBuffer, 1, bzBytesWritten, stdout);
fflush(stdout);
}
while (bzError != BZ_STREAM_END);
/* close stream */
bzError = BZ2_bzCompressEnd(&bzStream);
/* bzError checking... */
質問
- 計算
cumulativeBytesWritten
(具体的にはbzBytesWritten
) が間違っていますか?どうすれば修正できますか?
デバッグ ビルドでこれらの値を追跡してきましたが、値を「二重にカウント」しているようには見えませんbzBytesWritten
。この値はカウントされ、パスがcumulativeBytesWritten
成功するたびにインクリメントするために 1 回使用されます。BZ2_bzCompress()
bz_stream
または、状態フラグの正しい使用法を理解していませんか?
たとえば、次の例では、いくつかのバイトを送信し続ける限り、圧縮して bzip2 ストリームを開いたままにしますか?
bzError = BZ2_bzCompress(&bzStream, BZ_RUN);
bzStream.next_in
同様に、次のステートメントは、ポインターからアクセスできるバイトが少なくとも数バイトある限り( BZ_RUN
)、データを圧縮できBZ_FINISH
ますか?
bzError = BZ2_bzCompress(&bzStream, (bzStream.avail_in) ? BZ_RUN : BZ_FINISH);
- または、これらの低レベルの呼び出しをまったく正しく使用していませんか? 高レベルの呼び出しを使用して、圧縮されたデータのチャンクのグループを 1 つのメイン ファイルに継続的に追加する必要がありますか?
これにはおそらく簡単な解決策がありますが、何が問題なのかをデバッグする過程で数日間頭を悩ませてきましたが、あまり進歩していません. アドバイスありがとうございます。