Zlib 缩小输入大于原始输入字符串?

Zlib deflated input is larger than original input string of chars?

我对 zlib 压缩 char 类型字符串的输入感到有点困惑。下面我有发布的代码输出,我注意到 input 字符串与输出相比 shorter 以字节为单位。

未压缩的大小为 8 字节压缩后的大小为 12?我是不是看错了?

这是代码。

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <iostream>
#include "zlib.h"

void print( char *array, int length)
{
    for(int index = 0; index < length; index++)
        std::cout<<array[index];

    std::cout<<std::endl;
}
void clear( char *array, int length)
{
    for(int index = 0; index < length; index++)
        array[index] = 0;
}
int main()
{
    const int length = 30;
    char a[length] = "HHHHHHH";
    char b[length] = "";
    char c[length] = "";

    print( a, length);

    std::cout<<std::endl;
    uLong ucompSize = strlen(a)+1; // "string" + NULL delimiter.
    std::cout<<"ucompSize: "<<ucompSize<<std::endl;
    uLong compSize = compressBound(ucompSize);
    std::cout<<"compSize: "<<compSize<<std::endl;
    std::cout<<std::endl;
    // Deflate
    compress((Bytef *)b, &compSize, (Bytef *)a, ucompSize);
    std::cout<<"ucompSize: "<<ucompSize<<std::endl;
    std::cout<<"compSize: "<<compSize<<std::endl;
    print( b, length);
    std::cout<<std::endl;
    // Inflate
    uncompress((Bytef *)c, &ucompSize, (Bytef *)b, compSize);
    std::cout<<"ucompSize: "<<ucompSize<<std::endl;
    std::cout<<"compSize: "<<compSize<<std::endl;
    print( c, length);

    return 0;
}

这是输出。

HHHHHHH

ucompSize: 8
compSize: 21

ucompSize: 8
compSize: 12
x��     ��

ucompSize: 8
compSize: 12
HHHHHHH

Process returned 0 (0x0)   execution time : 0.013 s
Press ENTER to continue.

这些字节中至少有六个是压缩流前面的两个魔术字节 (header),将其标识为 zlib-compressed 文件,还有四个字节用于校验和。不计算格式的开销最多会留下六个字节的压缩数据,这比您的输入流要小。

有关文件格式的更多详细信息,请参阅 RFC 的 §2.2。您可以使用 xxdhexdump 等工具来调查十六进制字节组,以确认输出流的哪些部分是开销的,哪些是压缩数据。

如果您想避免这种情况,您可以使用 compressBound() 函数来检查大小是否实际上大于您当前的数据:

ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer.

compress() 函数使用 zlib 格式,在原始压缩数据周围放置 two-byte header 和 four-byte 尾部。即使原始压缩数据小于原始字符串,您也会从包装器中多获得六个字节。对于空字符串,根本没有字节,原始压缩数据是两个字节。所以 zlib 流的最小大小是八个字节。八个重复的输入字节可以产生短至四个字节的原始压缩数据,因此最小 zlib-wrapped 结果是十个字节。

一般来说,您需要更大的输入才能使无损压缩有效。