zlib的compress/uncompress仅处理内存数据,不支持文件i/o;生成zip需用minizip或zlib-ng;windowbits参数决定格式兼容性;缓冲区须用malloc/free统一管理。

zlib 的 compress 和 uncompress 只能处理内存数据,不能直接读写文件
这是最常踩的坑:看到函数名带“compress”,就以为能传个 "input.txt" 进去直接生成 "output.zip"。实际上 compress 和 uncompress 是 zlib 最底层的 DEFLATE 压缩/解压函数,只操作 unsigned char* 缓冲区,不碰文件 I/O。
真正要压缩文件,得自己:
- 用 fopen 读取原始文件到内存(或分块读)
- 调用 compress 处理这块内存
- 再用 fwrite 把结果写入新文件
- 解压同理,但要注意目标缓冲区大小必须足够——uncompress 不会自动扩容,给小了就返回 Z_BUF_ERROR
示例关键片段:
unsigned long destLen = sourceLen * 1.1 + 12; // 预估压缩后大小,+12 是 zlib header 开销 unsigned char* dest = new unsigned char[destLen]; int ret = compress(dest, &destLen, source, sourceLen); // 注意 destLen 是引用传入,会被改写
想生成 .zip 文件?别用 zlib 原生 API,改用 minizip 或 zlib-ng 的 zipOpen
标准 zlib 库根本不提供 ZIP 归档功能——它只实现 DEFLATE 算法。所谓“zip 文件”是 ZIP 格式(含目录结构、文件头、CRC、中央目录等),zlib 自带的 contrib/minizip 才封装了这部分逻辑。
如果你硬要用原生 zlib 拼 ZIP,等于重写 ZIP 规范解析器,极易出错。实际项目中建议:
立即学习“C++免费学习笔记(深入)”;
- 用
minizip(zlib 源码包里自带,需自己编译启用) - 或者直接切到更现代的
zlib-ng,它把zipOpen/zipWriteInFileInZip等接口整理得更清晰 - Windows 下可考虑
7z.dll或libzip,它们对多文件、密码、UTF-8 路径支持更稳
注意:minizip 默认不支持 ZIP64,大文件(>4GB)需定义 ZIP_USE_ZIP64 宏并确保调用链全量启用。
deflateInit2 的 windowBits 参数决定兼容性和格式,设错就打不开
这个参数控制 DEFLATE 的窗口大小和封装格式,直接影响输出能否被其他工具识别:
-
windowBits = 15:标准 DEFLATE 流(无头尾),gzip、Python zlib.decompress都能解,但 WinRAR / 7-Zip 默认不认 -
windowBits = -15:DEFLATE 流(负号表示去掉 zlib header/trailer),适合嵌入协议载荷 -
windowBits = 31:gzip 格式(RFC 1952),带 magic header 和 CRC,gunzip、浏览器fetch().then(r => r.arrayBuffer())都能直解
常见错误:用 deflateInit2(..., 15, ...) 压出数据,然后拿 gzip -d 去解——失败,因为 gzip 工具只认 windowBits=31 生成的流。反过来,用 31 压的流,若用 uncompress()(只认 zlib 格式)去解,也会报 Z_DATA_ERROR。
内存管理不匹配导致崩溃:malloc/free 和 new/delete 别混用
zlib 函数内部不管理用户传入的缓冲区内存,但很多示例代码忽略了分配方式一致性:
-
compress和uncompress的输入/输出缓冲区必须用malloc分配(zlib 内部可能调用realloc) - 如果用了
new unsigned char[],再传给uncompress,而它内部又尝试free()释放——未定义行为,大概率 crash -
deflate/inflate结构体里的zalloc/zfree回调也必须匹配:若用new分配z_stream,回调里就得用delete,否则泄漏
最省心做法:所有 zlib 相关缓冲区统一走 malloc/free;z_stream 实例本身用栈分配(z_stream stream;),避免手动管理。
复杂点在于跨平台时 malloc 对齐要求不同,尤其 ARM64 上某些 zlib 版本对未对齐指针敏感——建议用 aligned_alloc(C11)或 _aligned_malloc(MSVC)分配 >1KB 的缓冲区。









