使用bzip2低级别的程序来压缩数据块

4

概述

我正在使用libbzip2库中的低级别调用:BZ2_bzCompressInit()BZ2_bzCompress()BZ2_bzCompressEnd()来将数据块压缩到标准输出。我正在从更高级别的调用迁移工作代码,因为我有一串字节流进入,并希望将这些字节以离散块的形式压缩(一个“离散块”是包含一组感兴趣的令牌的一组字节 —— 我的输入在逻辑上被分成了这些块的组)。

完整的块组可能包含,比如说,500个块,我想要将它们压缩成一个bzip2流并写入到标准输出。

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

问题

问题在于我的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);
  • 或者,我完全没有正确使用这些低级调用吗?我应该回到使用较高级别的调用,将一组压缩的数据块连续附加到一个主文件上吗?

可能有一个简单的解决方案,但是在调试可能出现的问题时,我已经敲了几天的桌子,但进展不大。感谢您提供的任何建议。

1个回答

1
回答我自己的问题,看起来我在计算写入的字节数时出现了错误。我不应该使用total_out_*成员。以下更正方法可以正常工作:
bzBytesWritten = sizeof(bzBuffer) - bzStream.avail_out;

其余的计算如下。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接