zip中心目录从eocd记录的offset_of_start_of_central_directory字段指向位置开始;需先定位eocd(可能含zip64扩展),再按46字节头+变长字段解析每条目,优先信任中央目录元数据并校验一致性。

ZIP 中心目录结构在哪?怎么定位它?
ZIP 文件末尾固定有 EOCD(End of Central Directory)记录,长度至少 22 字节,它不存压缩数据,只存中心目录的起始偏移和条目数。真正要解析的中心目录(Central Directory)就从 EOCD 的 offset_of_start_of_central_directory 字段指向的位置开始——不是文件开头,也不是紧挨着文件头,而是靠后、甚至可能靠近结尾。
-
EOCD不一定在文件最末;它后面可能跟有 ZIP64 扩展签名(0x07064b50)或额外数据(如数字签名),必须先跳过这些才能准确定位 - 如果 ZIP 文件大于 4GB 或条目数 ≥ 65535,
EOCD本身无效,得找 ZIP64 的EOCD64 Locator和EOCD64 Record,它们藏在离文件末尾 20 字节处(Locator)和往前推若干字节的位置 - 直接用
fseek(file, -22, SEEK_END)读EOCD是常见错误:一旦有注释或 ZIP64 扩展,就会读错
中心目录每条记录的字段怎么解析?关键偏移和长度有哪些?
每个中心目录条目(Central Directory File Header)固定 46 字节基础结构,但实际长度可变(因含可选字段和文件名/注释等变长内容)。必须按顺序解析,不能跳:
- 前 4 字节必须是
0x02014b50(小端),否则不是合法条目 -
version_made_by(字节 4–5)决定是否含 UTF-8 路径名(高位 bit=11 表示 UTF-8) -
general_purpose_bit_flag(字节 6–7)第 11 bit 表示是否使用 data descriptor,影响后续数据区解析逻辑 -
file_name_length(字节 28–29)和extra_field_length(30–31)、file_comment_length(32–33)三者相加才是该条目总长度,缺一不可 -
relative_offset_of_local_header(字节 42–45)指向对应 Local File Header 的位置,用于反查原始压缩数据起始,不是中心目录内偏移
// 示例:读取一个条目的基础头(46 字节)
uint8_t header[46];
fread(header, 1, 46, file);
if (le32toh(*(uint32_t*)header) != 0x02014b50) { /* 错误 */ }
uint16_t name_len = le16toh(*(uint16_t*)(header + 28));
uint16_t extra_len = le16toh(*(uint16_t*)(header + 30));
uint16_t comment_len = le16toh(*(uint16_t*)(header + 32));
size_t total_len = 46 + name_len + extra_len + comment_len;
为什么用 std::ifstream 读到一半就乱码?编码和 null 截断问题怎么处理?
C++ 默认以文本模式打开文件会触发换行符转换(尤其 Windows 下 \r\n → \n),破坏二进制结构;而用 std::ios::binary 模式后,std::string 构造时若遇到中间的 <p>C++ 默认以文本模式打开文件会触发换行符转换(尤其 Windows 下 <code>\r\n → \n),破坏二进制结构;而用 std::ios::binary 模式后,std::string 构造时若遇到中间的 \0(比如文件名字段含空字节、或 extra field 含 binary 数据),会提前截断。
- 所有 ZIP 解析必须用
std::ifstream file(path, std::ios::binary) - 文件名、注释等字段必须用
std::vector<uint8_t></uint8_t>或std::string_view(C++17)配合原始指针+长度操作,绝不能用std::string(data, len)以外的方式隐式构造 - UTF-8 标志位为真时,文件名字段才可安全 reinterpret_cast 为
const char*传给std::string;否则可能是 IBM437 编码,需查表转换(Windows 默认 ZIP 打包器常用)
Local Header 和 Central Directory 不一致怎么办?如何验证一致性?
ZIP 规范允许 Local File Header 和 Central Directory 中的 CRC、压缩/未压缩大小字段不一致(例如打包工具未填 Local Header 的 CRC,只填了 Central Directory 的),但解析时应优先信任 Central Directory——它是“权威元数据”。
- 必须校验
file_name字段内容是否与对应 Local Header 的同名字段完全一致(字节级),否则可能是损坏或恶意构造 - 若
compressed_size在 Central Directory 为 0,但general_purpose_bit_flag第 3 bit 为 1(表示 data descriptor 存在),则真实压缩大小在 data descriptor 末尾,需向后搜索0x08074b50签名 - 某些工具(如某些版本的 7-Zip)会在 Central Directory 条目间插入 padding(全 0 字节),导致下一条目偏移计算错误;必须依赖每条目的前 4 字节签名跳转,不能靠累加长度硬算
中心目录结构看似线性,但 ZIP 的向后兼容设计让它的解析充满条件分支和隐式假设。最常被忽略的是 ZIP64 的 fallback 链路和 data descriptor 的存在性判断——这两个点一旦漏掉,哪怕能解出小文件,遇到真实生产环境 ZIP(尤其是构建产物或 CI 生成包)就会静默失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











