用libzip写zip文件最直接:调用zip_open()创建归档,zip_source_file()加载源文件,zip_file_add()添加条目(路径用/、显式传zip_fl_enc_utf_8),zip_set_file_compression()设压缩级别,最后zip_close()并手动zip_source_free()释放资源。

用 libzip 写 ZIP 文件最直接
标准 C++ 没有内置 ZIP 支持,必须依赖第三方库。libzip 是目前最轻量、API 清晰、跨平台(Linux/macOS/Windows)且维护活跃的选择。它不依赖 Boost 或 CMake 太深,编译简单,适合嵌入到已有项目中。
常见错误是试图用 zlib 自己拼 ZIP 结构——ZIP 不只是 deflate 压缩,还包含中央目录、本地文件头、CRC 校验等固定格式,手动实现极易出错或不兼容主流解压工具。
实操建议:
- Linux/macOS:用包管理器安装,如
apt install libzip-dev或brew install libzip - Windows:推荐用 vcpkg:
vcpkg install libzip:x64-windows,避免手动链接zlib和openssl(libzip默认只用 zlib,关掉 crypto 支持即可) - 确保链接时加上
-lzip -lz(Linux/macOS)或对应 .lib(Windows)
zip_open() 和 zip_file_add() 是核心流程
创建 ZIP 文件分三步:打开归档、添加文件、关闭归档。关键不是“怎么压缩”,而是“怎么让每个条目写对路径和属性”。
示例代码片段(省略错误检查,仅示意主干):
#include <zip.h>
zip_t *za = zip_open("out.zip", ZIP_CREATE, &err);
zip_source_t *src = zip_source_file(za, "input.txt", 0, 0);
zip_file_add(za, "input.txt", src, ZIP_FL_ENC_UTF_8);
zip_close(za);
</zip.h>
注意点:
-
zip_source_file()第二个参数是源路径,第三个参数为0表示读整个文件;若传 -1,会尝试 mmap,某些文件系统(如 NFS)可能失败 -
zip_file_add()第二个参数是 ZIP 内部路径,支持子目录,比如"data/config.json",但不要以/开头(否则部分解压器会忽略) -
ZIP_FL_ENC_UTF_8必须显式传,否则中文路径在 Windows 上大概率乱码 - 别忘了
zip_source_free(src)—— 即使zip_file_add()成功了,src仍需手动释放,否则内存泄漏
压缩级别控制靠 zip_set_file_compression()
libzip 默认用 ZIP_CM_DEFLATE,但不指定级别时等效于 zlib 的 Z_DEFAULT_COMPRESSION(约 6 级),不是最高压缩比。
如果需要更小体积或更快打包,得在 zip_file_add() 后立刻调用:
zip_int64_t idx = zip_name_locate(za, "input.txt", 0); zip_set_file_compression(za, idx, ZIP_CM_DEFLATE, 9);
说明:
-
zip_name_locate()返回内部索引,必须在zip_file_add()之后、zip_close()之前调用 - 压缩级别 0–9:0=不压缩(store),1=最快,9=最慢但最小;级别 >1 对文本类文件收益明显,对已压缩文件(如 JPG、MP4)设 9 没意义,还拖慢速度
- 不能对单个文件设
ZIP_CM_BZIP2或ZIP_CM_ZSTD,除非编译libzip时启用了对应后端,且运行时系统装了对应库
Windows 下路径分隔符和权限位容易出问题
在 Windows 上用 libzip 添加文件时,如果源路径含反斜杠 \,zip_source_file() 可能失败(返回 NULL);ZIP 内部路径若用 \,某些解压器(如 macOS 归档实用工具)会当成普通字符而非目录分隔符。
解决方案很实在:
- 源路径统一用正斜杠
/或用std::filesystem::path转换:p.replace_extension("").generic_string() - ZIP 内部路径一律用
/,哪怕在 Windows 编译;libzip会自动处理兼容性 - 别依赖
zip_file_get_external_attributes()读原始权限——Windows 没有 Unix 权限位,返回值不可靠;如需标记目录,添加条目时名字以/结尾(如"logs/"),并用zip_file_add()+ZIP_FL_ENC_UTF_8
真正麻烦的是,有些旧版 libzip(
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











