libzip 可直接读取 zip 中央目录获取文件名列表而无需解压;需用 zip_open() 打开、zip_get_num_entries() 获取条目数、zip_get_name() 逐个提取,注意错误检查与边界判断。

用 libzip 直接读取 ZIP 中央目录,不解压获取文件名列表
ZIP 文件结构本身支持“只读中央目录”,无需解压任何内容就能列出所有文件名。关键不是靠系统命令或临时解压,而是用支持随机读取 ZIP 格式的库——libzip 是最稳定、跨平台、被 cmake 和 pkg-config 广泛集成的选择。
常见错误是试图用 std::ifstream 手动解析 ZIP 结构:ZIP 中央目录位置不固定(可能在末尾带额外数据),且需处理 ZIP64 扩展、签名验证、编码(如 UTF-8 vs CP437),极易出错或漏文件。
- 安装时优先用包管理器:
apt install libzip-dev(Ubuntu)、brew install libzip(macOS) - 编译链接加
-lzip,CMake 中用find_package(libzip REQUIRED)+target_link_libraries(... zip) - 必须检查
zip_open()返回值,返回NULL时调用zip_error_strerror()才能看到真实原因(比如文件被占用、权限不足、非 ZIP 格式)
zip_get_num_entries() 和 zip_get_name() 的正确调用顺序
不能跳过条目数量直接循环;也不能对空字符串或 NULL 返回值不做判断就 printf。libzip 的 zip_get_name() 在索引越界或内部错误时返回 NULL,但不会崩溃——前提是先确认总条目数。
示例核心逻辑:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
zip_t *za = zip_open("archive.zip", 0, &err);
if (!za) { /* 错误处理 */ }
int n = zip_get_num_entries(za, 0); // 第二个参数为 0 表示不包含 ZIP 文件自身(即不递归子 ZIP)
for (int i = 0; i
-
zip_get_num_entries(za, ZIP_FL_UNCHANGED)可绕过重新扫描,但仅适用于刚打开、未做任何修改的 ZIP -
zip_get_name()第三个参数若传ZIP_FL_ENC_UTF_8,会在名称含非 ASCII 字符且源 ZIP 声明了 UTF-8 标志时生效;否则仍按原始字节返回 - Windows 上路径分隔符统一为
/(ZIP 规范强制),无需替换\
为什么不用 minizip 或 zlib 原生接口?
zlib 本身不支持 ZIP 文件结构解析,它只处理 DEFLATE 流;而 minizip(尤其是旧版)缺乏对 ZIP64、数据描述符、加密条目的健壮处理,且 API 易误用(例如 unzGoToFirstFile() 后必须配对 unzGoToNextFile(),漏调用会导致后续读取错位)。
-
libzip将 ZIP 当作“只读容器”设计,zip_open()内部自动定位中央目录、校验 EOCD(End of Central Directory)偏移,兼容性远高于手写解析 - 若项目已用 CMake,
FetchContent_Declare(zip URL "...")可直接拉取最新libzip源码编译,避免系统库版本过旧(如 Ubuntu 20.04 自带的 libzip 1.5.1 不支持某些 ZIP64 边界情况) - 不推荐用
system("unzip -l archive.zip"):启动进程开销大、输出格式不稳定(列宽变化、含 summary 行)、无法获取原始编码名、无错误码区分“文件不存在”和“密码错误”
遇到中文文件名乱码或显示为空怎么办
不是编码转换问题,而是 ZIP 创建时未设置通用位标志(General Purpose Bit 11)。libzip 默认按原始字节返回名称,如果压缩工具(如旧版 Windows 资源管理器)用了 CP936 但没设 UTF-8 标志,zip_get_name() 就会返回 GBK 编码的字节流——此时强行 reinterpret_cast 成 UTF-8 字符串必然乱码。
- 先用
zip_file_extra_field_get(za, i, ZIP_EXTRA_FIELD_GLOBAL, &len, 0)检查是否含 ZIP64 扩展或 UTF-8 标志位,但更实际的做法是:用file archive.zip看输出是否含UTF-8字样 - 若确认是 GBK 编码且必须显示,可用
iconv库转码,但注意:libzip 不提供内置转码函数,也**不建议**在核心路径中引入复杂字符处理 - 真正可靠的解法是控制上游:让压缩方使用
7z a -mcu=on archive.zip ...或zip -U(Info-ZIP 3.0+)显式启用 UTF-8
ZIP 文件名检索快慢几乎只取决于中央目录大小(通常几 KB),和压缩包体积无关。真正卡住的往往是磁盘 I/O(比如网络挂载盘)或错误地尝试读取每个文件头——只要坚持只调 zip_get_name(),几百 MB 或几个 GB 的 ZIP 都能在毫秒级返回全部文件名。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










