C++如何压缩和解压文件?(zlib库使用指南)

3次阅读

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

C++如何压缩和解压文件?(zlib库使用指南)

zlib 的 compressuncompress 只能处理内存数据,不能直接读写文件

这是最常踩的坑:看到函数名带“compress”,就以为能传个 "input.txt" 进去直接生成 "output.zip"。实际上 compressuncompress 是 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 规范解析器,极易出错。实际项目中建议:

  • minizip(zlib 源码包里自带,需自己编译启用)
  • 或者直接切到更现代的 zlib-ng,它把 zipOpen/zipWriteInFileInZip接口整理得更清晰
  • windows 下可考虑 7z.dlllibzip,它们对多文件、密码、UTF-8 路径支持更稳

注意:minizip 默认不支持 ZIP64,大文件(>4GB)需定义 ZIP_USE_ZIP64 宏并确保调用链全量启用。

deflateInit2 的 windowBits 参数决定兼容性和格式,设错就打不开

这个参数控制 DEFLATE 的窗口大小和封装格式,直接影响输出能否被其他工具识别:

  • windowBits = 15:标准 DEFLATE 流(无头尾),gzipPython 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 函数内部不管理用户传入的缓冲区内存,但很多示例代码忽略了分配方式一致性:

  • compressuncompress 的输入/输出缓冲区必须用 malloc 分配(zlib 内部可能调用 realloc
  • 如果用了 new unsigned char[],再传给 uncompress,而它内部又尝试 free() 释放——未定义行为,大概率 crash
  • deflate/inflate 结构体里的 zalloc/zfree 回调也必须匹配:若用 new 分配 z_stream,回调里就得用 delete,否则泄漏

最省心做法:所有 zlib 相关缓冲区统一走 malloc/freez_stream 实例本身用分配(z_stream stream;),避免手动管理。

复杂点在于跨平台时 malloc 对齐要求不同,尤其 ARM64 上某些 zlib 版本对未对齐指针敏感——建议用 aligned_alloc(C11)或 _aligned_malloc(MSVC)分配 >1KB 的缓冲区。

text=ZqhQzanResources