# 收到 ZIP 报表先别急着解压：用 zipfile 做清单、完整性和路径风险预检

## 文档明确的机制

自动化流程收到 ZIP 报表后，第一步不应直接 `extractall()`，而应先把文件当作待验收输入。Python 标准库 `zipfile` 提供了几个正好用于入站检查的能力。

首先，`zipfile.is_zipfile(filename)` 会根据 magic number 判断文件是否为有效 ZIP，返回 `True` 或 `False`；`filename` 也可以是文件对象或类文件对象。它适合做最外层格式识别，但通过这一判断不等于报表内容完整、成员齐全或路径安全。

确认可打开后，可以读取成员清单。文档说明，`ZipFile.infolist()` 会为归档中的每个成员返回一个 `ZipInfo` 对象；如果归档来自磁盘，返回顺序与实际 ZIP 中条目顺序一致。`ZipFile.namelist()` 则返回成员名称列表。前者适合保留成员元信息，后者适合直接做名称集合比对。

完整性检查可使用 `ZipFile.testzip()`。文档明确：它会读取归档中的所有文件，检查 CRC 和文件头；如果发现第一个坏文件，就返回该文件名，否则返回 `None`。因此，预检报告可以把结果记录为“发现坏成员：名称”或“未发现坏文件”，而不是只凭程序能打开归档就判定通过。

路径风险方面，需要准确理解 `extract()` 和 `extractall()` 的边界。文档对 `extract(member, path=None, pwd=None)` 的说明是：成员文件名如果是绝对路径，盘符、UNC 共享点和开头的斜杠会被剥离，例如 Unix 上 `///foo/bar` 变为 `foo/bar`，Windows 上 `C:\foo\bar` 变为 `foo\bar`；成员文件名中的所有 `..` 组件会被移除，例如 `../../foo../../ba..r` 变为 `foo../ba..r`；Windows 上的非法字符会替换为下划线。

同时，`extractall()` 的警告写得很明确：不要未经预先检查就解压来自不可信来源的归档；归档中可能有绝对文件名或含 `..` 组件的成员，模块会尝试防止文件创建在目标 `path` 之外，并指向 `extract()` 的说明。

还需特别区分 `zipfile.Path`。文档说明，`Path` 类不会净化 ZIP 内文件名；与 `extract()`、`extractall()` 不同，调用方有责任验证或净化文件名，以防止绝对路径或含 `..` 组件导致路径穿越。因此，不能把“使用了 `zipfile.Path`”当成已经完成路径防护。

## 团队自行约定的接手建议

> 以下是团队流程建议，不是 `zipfile` 文档声称自动提供的完整验收能力。

建议把入站验收拆成四层结果，并在解压前全部落盘或记录到任务日志：

1. **格式结果**：记录 `is_zipfile()` 的布尔结果；失败时不再继续打开或解压。
2. **成员清单**：用 `infolist()` 保存每个 `ZipInfo` 成员，或至少用 `namelist()` 保存名称列表。
3. **业务文件核对**：将实际成员名称集合与预期清单比较，单独列出缺失文件和多余文件。预期文件名、目录层级和允许的多余项应由团队流程定义，文档本身不会判断业务上“应该有哪些报表”。
4. **完整性结果**：调用 `testzip()`，把返回的第一个坏成员名称或 `None` 写入验收结果。

路径风险清单也建议在解压前生成。检查范围可限定为文档明确提到的两类原始成员名：是否为绝对路径，或是否包含 `..` 组件。命中时不要把它们静默改名后当作通过，而应标为风险成员，交给流程决定拒绝、人工复核还是按既定规则处理。

预检通过后，团队可约定只解压白名单成员，并指定一个隔离的目标目录；不要从当前工作目录直接开始解压。这里的“白名单”和“隔离目录”属于接手规范：白名单内容来自报表约定，隔离目录用于限制写入位置。调用 `extract()` 或 `extractall()` 时，应显式传入 `path`，并只把已经核对过的成员交给 `members` 参数；`extractall()` 文档也说明 `members` 必须是 `namelist()` 返回列表的子集。

如果代码通过 `zipfile.Path` 遍历或读取成员，不要期待它替你净化路径；团队应在自己的检查步骤中先处理绝对路径和 `..` 风险，再进行后续读取。

## 边界与总结

本文只覆盖“自动化流程接收一个 ZIP 文件路径后，在解压前做入站预检”的场景，不扩展到分卷 ZIP，也不介绍创建加密 ZIP。文档明确说明：该模块不处理 multipart ZIP 文件；支持解密 ZIP 归档中的加密文件，但不能创建加密文件，且解密是用原生 Python 实现，速度非常慢。

还应避免两个过度承诺：第一，`is_zipfile()`、`testzip()` 和清单核对解决的是格式、CRC、文件头及成员层面的验收，不能替代业务内容校验；第二，`extract()`/`extractall()` 的路径处理不能被描述为“自动消除所有路径风险”，而 `zipfile.Path` 更明确不做净化。

稳妥的入站顺序是：先识别 ZIP，再列出成员，核对缺失与多余项，执行 CRC 和文件头检查，标记绝对路径或含 `..` 的成员；只有预检满足团队规则后，才按白名单解压到指定隔离目录。这样能把文档已提供的机制与团队自行承担的流程判断清楚分开。

## 相关工具

[AI 工作流 ROI 诊断器](/demos/ai-workflow-roi-diagnostic/index.html) · 查看工具的输入要求、输出说明与适用范围。


来源：[收到 ZIP 报表先别急着解压：用 zipfile 做清单、完整性和路径风险预检](https://docs.python.org/3/library/zipfile.html)
