libzip可安全读取加密ZIP的文件名(不需密码),因其将元数据访问与内容解密完全解耦;用zip_open()配ZIP_RDONLY标志打开,再通过zip_get_num_entries()和zip_get_name()遍历即可。

用 libzip 读取 ZIP 中的加密文件名(不需解密)
ZIP 文件中加密条目(如使用传统 PKWARE 加密或 AES 加密)的文件名本身**不加密**,只加密文件内容。所以只要 ZIP 结构完整、中央目录未损坏,就能安全读取文件名列表——无需密码,也不触发解密流程。
关键在选对库和 API:C++ 标准库不支持 ZIP,必须依赖第三方;libzip 是目前最稳的选择,它把“列出条目”和“解密/解压”完全解耦。
-
zip_open()打开 ZIP 时传ZIP_RDONLY标志,不校验加密字段,避免早期版本因 AES 标志位异常报错 - 用
zip_get_num_entries()+zip_get_name()遍历,这两个函数完全绕过内容解密逻辑 - 若 ZIP 使用了非标准扩展(如某些 WinRAR 生成的 ZIP),
zip_open()可能返回NULL;加ZIP_CHECKCONS标志可增强容错,但会略慢
为什么 minizip 和 zlib 原生接口不适合这个需求
zlib 本身不处理 ZIP 容器格式,只提供 DEFLATE 压缩算法;minizip(zlib 附带的工具集)虽能列文件,但它的 unzGoToFirstFile() / unzGetCurrentFileInfo() 在遇到加密条目时,部分旧版本会强制要求设置密码(哪怕只读文件名),导致无密码时直接失败或崩溃。
而 libzip 明确区分了“元数据访问”和“内容访问”,加密状态只影响 zip_fopen() 等打开数据流的函数,不影响 zip_get_name()。
立即学习“C++免费学习笔记(深入)”;
- 常见错误现象:
unzGetCurrentFileInfo()返回UNZ_BADZIPFILE或卡死,实际 ZIP 是合法的,只是含 AES 条目 - Windows 上用 MinGW 编译
minizip时,若没定义USE_WIN32_IOAPI,加密 ZIP 的路径读取可能乱码(UTF-8 vs GBK) -
libzip默认用 UTF-8 解释文件名,兼容性更好;minizip依赖本地 locale,中文路径易出错
处理 ZIP 中的非 ASCII 文件名(中文、emoji 等)
ZIP 规范本身不强制编码,实际中常见两种情况:传统 DOS 风格(CP437)、现代 ZIP 工具(如 7-Zip、macOS 归档工具)设 EFS(Extended File System)标志,表示文件名是 UTF-8。libzip 会自动检测并转成 UTF-8 字符串返回——但前提是 ZIP 创建时正确设置了标志位。
- 如果文件名显示为乱码(如
.txt),大概率是 ZIP 创建方没设 EFS 位,且用了系统默认编码(如 Windows 上是 GBK) - 此时不能靠猜测解码,应调用
zip_get_file_comment()或检查zip_stat_t中的flags字段,确认ZIP_STAT_ENCRYPTION和ZIP_STAT_UTF8_NAME是否置位 - libzip 3.0+ 版本支持
zip_set_default_password(),但仅用于后续zip_fopen();对列名无任何影响,别误以为要先设密码才能看到名字
编译与链接 libzip 的最小依赖注意点
libzip 依赖 zlib,但**不需要** openssl 或 mbed TLS 就能读取加密条目的文件名——AES 解密才需要它们。如果你只列名,关掉加密后端可大幅简化构建。
- CMake 中加
-DENABLE_GNUTLS=OFF -DENABLE_OPENSSL=OFF -DENABLE_MBEDTLS=OFF,避免引入多余 SSL 库 - Linux 上用包管理器安装时,优先选
libzip-dev(Debian/Ubuntu)或libzip-devel(RHEL/Fedora),别只装libzip5运行时,否则链接失败 - Windows 上若用 vcpkg:
vcpkg install libzip:x64-windows即可,默认已禁用加密后端;手动编译时确保ZLIB_INCLUDE_DIR指向正确的 zlib 头文件路径,否则zip.h里会报zlib.h找不到
真正容易被忽略的是:有些 ZIP 工具(比如老版本 Bandizip)会在中央目录前插入自定义签名或冗余数据,导致 libzip 的 zip_open() 直接失败。这时得先用 hexdump -C file.zip | head -20 看前几个字节是不是标准的 PK\x03\x04 ——如果不是,说明 ZIP 被“壳化”或损坏,再强的库也读不了名字。



















