Watch at Ease看见世界,读懂生活。

科技 · 实用指南

ZIP 能列文件却读不出来?逐项检查成员与 Python 解码支持

四个受控 ZIP 样本说明:目录可读、不支持压缩方法和 CRC 错误,需要分别判断。

原创示意图:Python 3.12.14 下四个自制双成员 ZIP 样本,区分目录可读、不支持方法和 CRC 错误。
原创示意图:Python 3.12.14 下四个自制双成员 ZIP 样本,区分目录可读、不支持方法和 CRC 错误。 Watch at Ease

如果 zipfile 能列出压缩包,却在读取某个文件时抛出 NotImplementedError,应检查该成员以及实际运行任务的 Python。能读取目录或前面的成员,并不能证明压缩包中的全部压缩、加密特性都受支持。

我们用 Python 3.12.14 测试四个微型双成员样本:它们都能列出文件并读出 readme.txt,但读取 data.csv 时分别出现成功、不支持方法异常和 CRC 错误。这些结果对应不同的排查方向。

记录实际读取器和每个成员

先在报错进程中记录 sys.version 和 zipfile.__file__,再以只读方式打开工作副本,遍历 z.infolist(),记录每个成员的 filename、compress_type、flag_bits、file_size 和 compress_size。定时任务、运行环境或同名模块遮蔽,都可能让实际读取器与另一个环境中检查的不同。

这只是清单检查,并未读取有效载荷。不要用第一个成员的方法代表全部成员,也不要将 is_zipfile() 成功视为全部内容可读。PKWARE 方法表还区分 Deflate64(9)和 AE-x 加密标记(99);解决 Zstandard 支持不等于解决这些分支。

把三种检测结果分开记录

每个样本先放入以存储方式保存的 readme.txt,随后放入相同的 24 字节 data.csv。存储加 Deflate(0/8)能返回预期 CSV,testzip() 返回 None;存储加 Zstandard(0/93)和旧 Zstandard 编号(0/20)都能读取说明文件,却在读取 CSV 时抛出 NotImplementedError,testzip() 也向外抛出该异常。

第四个样本使用 Deflate,但故意写错 CRC 元数据。读取 data.csv 抛出 BadZipFile,testzip() 则返回文件名。必须区分“抛出异常”“返回坏文件名”和 None:解码方法不受支持时,CRC 尚未得到验证,不能据此判断内容损坏或完好。

核对内置支持,不能只看是否安装了包

已安装的 zstandard 0.25.0 能独立解压我们制作的 Zstandard 数据帧,但导入它不会给 Python 3.12.14 的 zipfile 增加 ZIP_ZSTANDARD。独立编解码库可用,不代表 ZIP 读取器会调用它;应核对实际解释器、模块以及该构建的文档能力。

Python 3.14 参考文档说明 ZIP_ZSTANDARD 在 3.14 加入,依赖 compression.zstd,读取时支持方法编号 20 和 93,写入使用 93。这是特定版本的文档说明,并非本文对 3.14 安装环境的实测,也不保证升级后能处理所有压缩、加密或归档特性。

选择兼容路径,再验证必需内容

按每个必需成员的压缩和加密特性,核对具体读取器的文档支持。必要时换用文档明确支持的读取器,或请提供方另导出兼容副本,同时保留原件。不要修改文件头中的方法编号,也不要降低加密强度来消除报错。Apache ZIP 指南已介绍逐成员能力检查;已有方法 9、99 的讨论各自对应不同特性。

随后在有适当限制的环境中读取全部必需成员,核对 CRC 结果并验证应用所需内容。本文四个微型未加密样本的 12 项断言均通过,未执行解压落盘;这些测试不证明不可信归档的安全性,也不覆盖 ZIP64、分卷或所有 Python 构建。所链接的通用 ZIP 指南解释结构、CRC 和必需内容的独立验证步骤。

原创示意图:先核对实际运行环境、每个必需成员与读取器文档能力,再验证有效载荷和应用内容。
原创示意图:先核对实际运行环境、每个必需成员与读取器文档能力,再验证有效载荷和应用内容。 Watch at Ease