当前位置:首页 > 文章列表 > 文章 > python教程 > Python zipfile.Path 怎样读取压缩包内的嵌套资源

Python zipfile.Path 怎样读取压缩包内的嵌套资源

来源:17golang原创 2026-11-14 06:10:54 0浏览 收藏

处理 ZIP 包时,最容易卡住的场景不是“怎么解压”,而是只想读取其中一个多级目录里的配置或模板,却不想把整个压缩包落到本地。zipfile.Path 可以把 ZIP 内部表示成一棵可遍历的虚拟路径树:从根节点开始用 / 或 joinpath() 进入目录,再用 read_text()、read_bytes() 或 open() 读取目标文件。

官方地址:https://docs.python.org/3/library/zipfile.html

要点是把“路径拼接”和“路径安全”分开处理:zipfile.Path 负责访问 ZIP 内的虚拟节点,但不会替你校验不可信成员名。可信来源可以直接按层读取;外部上传的 ZIP 则要先检查成员名,再进行读取或解压。

问题现场:嵌套文件不想先解压

假设压缩包里有这样的结构:

project.zip
├── config/
│   └── app/
│       └── settings.json
└── docs/
    └── readme.txt

传统做法是先调用 extractall(),然后用本地路径读取 config/app/settings.json。如果只需要查看一个小文件,这会多出临时目录、清理目录和文件名冲突等问题。zipfile.Path 提供的是另一条路径:ZIP 仍保持打开状态,代码只在压缩包内部定位和读取目标成员。

ZIP 压缩包根目录通过 zipfile.Path 逐层走到 config app settings json 的结构说明图
图1:zipfile.Path 在 ZIP 内逐层定位嵌套资源的静态结构图,不是运行截图。

初步判断:先从根节点观察结构

不要一开始就把目标路径写死。先把 ZipFile 交给 zipfile.Path,再通过 iterdir() 查看根节点的直接子项。这样可以区分“目录名写错”和“目标文件确实不存在”这两类问题。

from pathlib import Path
from zipfile import Path as ZipPath
from zipfile import ZipFile

archive = Path("project.zip")

with ZipFile(archive) as zf:
    root = ZipPath(zf)
    for child in root.iterdir():
        # 这里只观察 ZIP 根目录的直接子项,不会递归展开全部成员。
        kind = "目录" if child.is_dir() else "文件"
        print(f"{kind}: {child.name}")

这里的 root 不是磁盘上的目录,它代表 ZIP 内部的空路径。iterdir() 只列当前节点的子项;遇到目录时可以继续调用 iterdir(),遇到文件时则应进入读取分支。

动手验证:拼接并读取嵌套资源

确认根节点结构后,就可以用 / 操作符写出和目录层级一致的路径。下面的例子只读取 settings.json,不把它解压到工作目录。

import json
from pathlib import Path
from zipfile import Path as ZipPath
from zipfile import ZipFile

with ZipFile(Path("project.zip")) as zf:
    root = ZipPath(zf)
    settings = root / "config" / "app" / "settings.json"

    if not settings.exists():
        # 先判断成员是否存在,把路径拼写错误和读取异常区分开。
        raise FileNotFoundError(settings.at)
    if not settings.is_file():
        # 目标若是目录,不能直接按 JSON 文件读取。
        raise IsADirectoryError(settings.at)

    text = settings.read_text(encoding="utf-8")
    config = json.loads(text)
    print(config.get("environment", "unknown"))

joinpath("config", "app", "settings.json") 也可以表达同样的路径。较新的 Python 版本还支持 Path.open() 的文本和二进制模式;要读取二进制资源时可以使用 read_bytes(),避免先把内容错误地解码成文本。

from zipfile import Path as ZipPath
from zipfile import ZipFile

with ZipFile("project.zip") as zf:
    root = ZipPath(zf)
    icon = root.joinpath("assets", "icons", "app.bin")
    if icon.is_file():
        # 二进制资源直接保留 bytes,避免编码转换造成数据损坏。
        payload = icon.read_bytes()
        print(f"读取字节数: {len(payload)}")

定位原因:Path 不负责路径安全

如果 ZIP 来自用户上传、第三方下载或消息附件,不能因为使用了 zipfile.Path 就认为路径安全。Python 官方文档明确提示:与 ZipFile.extract() 和 extractall() 会尝试处理成员名不同,Path 不会清理压缩包内的绝对路径或 .. 路径,调用方需要自行校验。

这也是两个容易混淆的边界:

  • zipfile.Path 的职责是访问 ZIP 内的虚拟路径;它不会把文件写到磁盘。
  • extract() 或 extractall() 的职责是写出文件,写出前应防止成员名逃逸目标目录。
zipfile.Path 读取前进行成员名规范化和安全边界判断的流程说明图
图2:读取嵌套资源前的成员名安全边界说明图,不是运行截图。

修复方案:建立安全成员名边界

一个实用的做法是先遍历 ZipInfo 的成员名,只允许相对路径,并拒绝包含空成员、绝对路径或父级跳转的条目。校验通过后,再把确定的相对路径交给 ZipPath 访问。

import posixpath
from pathlib import PurePosixPath
from zipfile import Path as ZipPath
from zipfile import ZipFile


def is_safe_member(name: str) -> bool:
    # ZIP 成员统一按正斜杠处理,拒绝绝对路径和父级跳转。
    normalized = posixpath.normpath(name.replace("\\", "/"))
    parts = PurePosixPath(normalized).parts
    return bool(name) and normalized != "." and not normalized.startswith("/") and ".." not in parts


with ZipFile("project.zip") as zf:
    unsafe = [info.filename for info in zf.infolist() if not is_safe_member(info.filename)]
    if unsafe:
        # 不可信归档中只要出现越界成员,就停止后续读取流程。
        raise ValueError(f"发现不安全的 ZIP 成员: {unsafe[:3]}")

    root = ZipPath(zf)
    target = root.joinpath("config", "app", "settings.json")
    if target.is_file():
        # 通过成员名检查后,再读取目标文件的文本内容。
        settings_text = target.read_text(encoding="utf-8")

这段检查解决的是成员名的路径边界,不等于完整的资源安全策略。生产代码还应按业务限制压缩包总大小、成员数量和单个文件大小,并对编码、重复成员名和损坏归档单独处理。

验证结果:把读取流程固定成几个判断

回到最开始的嵌套资源问题,可以把判断顺序固定下来:先打开 ZipFile,再从 ZipPath(zf) 根节点拼接路径;路径不确定时用 iterdir() 观察;目标节点先判断 exists(),再用 is_file() 或 is_dir() 区分类型;文本、二进制和流式读取分别选择对应方法;外部归档则在读取前检查成员名。

场景推荐写法需要留意
查看根目录ZipPath(zf).iterdir()只返回当前层级子项
访问嵌套文件root / "a" / "b.txt"这是 ZIP 内的虚拟路径
读取文本path.read_text(encoding="utf-8")确认文件编码
读取二进制path.read_bytes()不要误用文本解码
处理外部归档先检查 ZipInfo.filenamePath 不替你清理越界成员

常见问题

zipfile.Path 能直接替代 pathlib.Path 吗?

不能完全替代。两者都有路径拼接和遍历的表达方式,但 zipfile.Path 指向 ZIP 内部成员,不代表本地文件系统;它的读取、写入和安全语义也由 ZIP 容器决定。

为什么 iterdir() 看不到我以为存在的目录?

ZIP 格式允许目录条目缺失,文件名本身也可能带有多级前缀。可以先查看 zf.namelist() 或逐层遍历,再根据实际成员名拼接路径,不要假设每一级都有独立的目录条目。

Path 读取之前一定要解压吗?

不一定。只读文本或二进制成员时,可以保持 ZipFile 打开并直接读取;需要让其他程序使用真实磁盘路径,或需要批量落盘时,才考虑解压流程。

总结

zipfile.Path 适合把“读取 ZIP 内某个嵌套资源”写成清晰的路径操作:从根节点开始遍历,按层拼接,按节点类型判断,再选择文本、字节或打开流。真正容易出问题的地方在安全边界:对于不可信压缩包,路径访问不会自动替你清洗成员名,必须把成员名校验、资源大小限制和异常处理放在读取流程之前。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python sqlite3 blob 写入后怎样控制事务提交Python sqlite3 blob 写入后怎样控制事务提交
上一篇
Python sqlite3 blob 写入后怎样控制事务提交
Python TypeIs 为什么比 TypeGuard 更适合否定分支
下一篇
Python TypeIs 为什么比 TypeGuard 更适合否定分支
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    1019次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    1021次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1155次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1122次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    963次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码