【问题标题】:Using bzip2 low-level routines to compress chunks of data使用 bzip2 低级例程压缩数据块
【发布时间】:2012-10-25 08:56:23
【问题描述】:

概述

我正在使用libbzip2 库中的低级调用:BZ2_bzCompressInit()BZ2_bzCompress()BZ2_bzCompressEnd() 将数据块压缩到标准输出。

我正在从更高级别的调用迁移工作代码,因为我有一个字节流进入,我想在离散块的 sets 中压缩这些字节(一个 discrete chunk 是一组字节,其中包含一组感兴趣的标记——我的输入在逻辑上分为这些块的组。

一组完整的块可能包含 500 个块,我想将其压缩为一个 bzip2 流并写入标准输出。

在一组中,使用我在下面概述的伪代码,如果我的示例缓冲区能够一次容纳 101 个块,我将打开一个新流,在 101、101、101、101 和 101 的运行中压缩 500 个块最后一次运行 96 个块,关闭流。

问题

问题是我的bz_stream 结构实例,它在BZ2_bzCompress() 例程的单次传递中跟踪压缩字节的数量,似乎声称写入的压缩字节比最终的总字节多, 压缩文件。

例如,压缩输出可能是一个真实大小为 1234 字节的文件,而报告的压缩字节数(我在调试时跟踪)略高于 1234 字节(比如 2345 字节)。

我的粗略伪代码分为两部分。

第一部分是我如何压缩一个块子集的粗略草图(我知道在这个子集之后还有另一个子集):

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 值。每次成功通过BZ2_bzCompress() 后,此值将被计数并使用一次以增加cumulativeBytesWritten

  • 或者,我不理解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);
  • 或者,我根本没有正确使用这些低级调用吗?我是否应该重新使用更高级别的调用来不断地将一组压缩的数据块附加到一个主文件中?

这可能有一个简单的解决方案,但是在调试可能出现的问题的过程中,我已经在桌面上敲了几天的头,而且我没有取得太大进展。谢谢你的建议。

【问题讨论】:

    标签: c compression bzip2


    【解决方案1】:

    在回答我自己的问题时,我似乎误算了写入的字节数。我不应该使用total_out_* 成员。以下更正工作正常:

    bzBytesWritten = sizeof(bzBuffer) - bzStream.avail_out;
    

    其余的计算如下。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多