首页 > 解决方案 > 在zlib编程中,CHUNK大小会影响压缩文件大小吗?

问题描述

我在 Linux 平台上使用 C 编程语言。参考zlib官网(http://www.zlib.net/zlib_how.html)上的zlib使用示例,编写了一个压缩程序。请注意,我的压缩方法是 gzip,这意味着使用 deflateint2() 函数而不是 deflateinit()。

根据 zlib 的网站,“CHUNK 只是用于向 zlib 例程提供数据和从 zlib 例程中提取数据的缓冲区大小。更大的缓冲区大小会更有效,尤其是对于 inflate()。如果内存可用,则缓冲区大小大约为应该使用128K或256K字节。”所以我认为CHUNK越大,压缩文件越小,压缩速度越快。

但是当我测试我的程序时,我发现无论CHUNK大小是16384还是1,压缩后的文件大小都是一样的(16384是zlib官方给出的典型值)。不同的是,当chunk size为1时,压缩速度要慢很多。

这个结果让我很困惑。我认为当 CHUNK 大小为 1 时,压缩处理是无效的。因为在这个例程中,每个输入的 CHUNK 都会被处理并直接输出到一个压缩文件中,我认为 1 字节的数据是无法压缩的。

所以我的问题是,为什么 CHUNK 大小只影响压缩速度,而不影响压缩率?

这是我的程序:

#define CHUNK 16384
int def(FILE *source, FILE *dest, int level, int memLevel)
{
    int ret, flush;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    ret = deflateInit2(&strm, level, Z_DEFLATED, MAX_WBITS + 16, memLevel, Z_DEFAULT_STRATEGY);
    if (ret != Z_OK)
        return ret;

    /* compress until end of file */
    do {
        strm.avail_in = fread(in, 1, CHUNK, source);
        if (ferror(source)) {
            (void)deflateEnd(&strm);
            return Z_ERRNO;
        }
        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
        strm.next_in = in;

        /* run deflate() on input until output buffer not full, finish
           compression if all of source has been read in */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = deflate(&strm, flush);    /* no bad return value */
            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
            have = CHUNK - strm.avail_out;
            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
                (void)deflateEnd(&strm);
                return Z_ERRNO;
            }
        } while (strm.avail_out == 0);
        assert(strm.avail_in == 0);     /* all input will be used */

        /* done when last data in file processed */
    } while (flush != Z_FINISH);
    assert(ret == Z_STREAM_END);        /* stream will be complete */

    /* clean up and return */
    (void)deflateEnd(&strm);
    return Z_OK;
}

标签: clinuxzlib

解决方案


因为 deflate 在内部缓冲数据以进行压缩。无论您如何将数据提供给 deflate,它都会累积并压缩字节,直到它有足够的空间发出 deflate 块。

你是正确的,你不能压缩一个字节。如果您想看看这是多么真实,那么flushZ_NO_FLUSHto更改Z_FULL_FLUSH然后一次输入一个字节。然后确实 deflate 将尝试分别压缩输入的每个字节。


推荐阅读