zlib压缩内存数据前必须初始化z_stream结构体并调用deflateInit(),循环调用deflate()直至Z_STREAM_END,最后调用deflateEnd()释放资源;输出为裸DEFLATE流,无header,需根据需求用deflateInit2()指定windowBits以兼容gzip或zlib格式。

zlib压缩内存数据前必须初始化z_stream结构体
不初始化就调用deflateInit()会导致未定义行为,常见表现是程序崩溃或返回Z_STREAM_ERROR。必须显式清零z_stream并设置zalloc/zfree为Z_NULL(否则Windows下可能触发访问违规):
z_stream zs;
memset(&zs, 0, sizeof(zs));
int ret = deflateInit(&zs, Z_BEST_COMPRESSION);
if (ret != Z_OK) {
// 处理错误,如Z_MEM_ERROR
}
注意deflateInit2()可指定窗口大小和压缩算法,但内存压缩场景通常用默认deflateInit()更安全。
压缩时要循环调用deflate()直到Z_STREAM_END
内存压缩不是一调就完的事。deflate()可能只处理部分输入,尤其当输出缓冲区不够大时,它会返回Z_OK并等待下次调用。必须用循环驱动,否则会丢数据:
- 每次调用前设置
zs.next_in指向待压数据起始,zs.avail_in设为剩余字节数 -
zs.next_out指向输出缓冲区,zs.avail_out设为剩余空间 - 检查返回值:
Z_OK继续,Z_STREAM_END表示完成,Z_BUF_ERROR说明输出缓冲区满需扩容
示例关键逻辑:
立即学习“C++免费学习笔记(深入)”;
zs.next_in = input_data;
zs.avail_in = input_size;
do {
zs.next_out = output_buffer + total_out;
zs.avail_out = output_capacity - total_out;
int ret = deflate(&zs, Z_FINISH);
if (ret == Z_STREAM_END) break;
if (ret == Z_BUF_ERROR) {
// 扩容output_buffer并重试
}
} while (zs.avail_in > 0);
别忘了调用deflateEnd()释放资源
忘记调用deflateEnd()会导致zlib内部分配的内存泄漏,尤其在频繁压缩的场景下会快速耗尽堆空间。它必须在所有deflate()调用完成后、且确认不再使用该z_stream时调用:
- 即使
deflateInit()失败,也要检查zs.opaque是否非空再决定是否调用deflateEnd() - 若中途出错(如
Z_MEM_ERROR),仍需调用deflateEnd()清理已分配的部分资源 - 调用后不能再访问
zs结构体,否则可能读到野指针
压缩后的数据不含header,直接写入文件可能无法被通用解压工具识别
zlib原生压缩输出是纯DEFLATE流,没有gzip或zlib封装头。如果目标是生成.gz文件或让gunzip能直接解压,得手动加gz_header或改用gzwrite()——但那是文件I/O接口,不适用于纯内存场景。若需兼容标准工具:
- 用
deflateInit2()传入-15作为windowBits参数可禁用zlib header,得到裸DEFLATE(适合嵌入协议) - 传
+31则启用gzip header(兼容gunzip),但需确保输出缓冲区多留18字节空间 - 传
+15是默认zlib格式(带4字节header+4字节adler32),多数C++项目用这个就够了
裸DEFLATE流本身合法,但别指望file命令或双击解压能认出来——它就是一段没包装的压缩字节。


















