pathlib文件路径处理

现代化的文件系统路径操作

学习主题: Python pathlib 模块深入讲解

核心内容: PurePath与Path的区别、路径创建与拼接、路径属性、文件操作、目录遍历、文件信息、路径解析、Path vs os.path对比

关键词: Python, pathlib, Path, 文件路径, 目录操作, glob, 文件系统

一、概述:为什么使用 pathlib

pathlib 是 Python 3.4 引入的标准库模块,提供了一套面向对象的文件系统路径操作接口。自 Python 3.6 起,pathlib 被正式认定为标准库的核心组成部分,在 Python 3.9 及之后版本中,Path 类已经可以作为 open() 等内置函数的直接参数使用。

pathlib 出现之前,Python 开发者主要依赖 os.path 模块进行路径操作。os.path 使用字符串来表示路径,所有操作都以函数调用的方式进行,代码可读性较差且容易出错。pathlib 的诞生彻底改变了这一现状——它将路径抽象为对象,所有操作都封装在对象的方法和属性中,代码更加直观、简洁且跨平台。

pathlib 的核心优势

  • 面向对象: 路径是对象而非字符串,拥有丰富的属性和方法
  • 跨平台: 自动处理 POSIX(Linux/macOS)与 Windows 的路径分隔符差异
  • 可组合: 使用 / 运算符即可拼接路径,简洁直观
  • 功能完备: 覆盖了文件读写、目录遍历、路径解析、文件信息查询等全场景
  • 与标准库兼容: Python 3.6+ 中可与 open()os 等无缝配合

一个直观的对比

先看一个简单的例子,对比传统 os.path 方式和 pathlib 方式的差异:

# -------- os.path 方式(传统) -------- import os base_dir = "/home/user/projects" file_path = os.path.join(base_dir, "data", "config.json") if os.path.exists(file_path): with open(file_path, "r") as f: content = f.read() name, ext = os.path.splitext(os.path.basename(file_path)) # -------- pathlib 方式(现代)-------- from pathlib import Path base_dir = Path("/home/user/projects") file_path = base_dir / "data" / "config.json" if file_path.exists(): content = file_path.read_text() name = file_path.stem ext = file_path.suffix

可以清晰地看到,pathlib 方式代码更短、语义更清晰。/ 运算符直接用于路径拼接,read_text() 一步完成读取,stemsuffix 直接作为属性访问,无需调用函数组合。

二、PurePath 与 Path 的区别

pathlib 模块的类体系分为两大层次:纯路径(PurePath)具体路径(Path)。理解二者的区别是掌握 pathlib 的第一步。

PurePath —— 纯路径对象

PurePath 是路径的抽象表示,只进行字符串级别的路径操作,不涉及任何实际的 I/O 操作。它永远不会访问文件系统,因此即使路径指向一个不存在的文件,也能正常创建和使用。它在底层有两个子类:

  • PurePosixPath —— 适用于 POSIX(Linux/macOS)风格的路径(使用 / 分隔符)
  • PureWindowsPath —— 适用于 Windows 风格的路径(使用 \ 分隔符,含盘符)

Path —— 具体路径对象

Path 继承自 PurePath,在纯路径的基础上增加了所有涉及文件系统 I/O 的操作,包括文件读写、目录创建删除、文件信息查询、符号链接操作等。Path 同样有两个子类:

  • PosixPath —— Unix/Linux 环境下的具体路径
  • WindowsPath —— Windows 环境下的具体路径

PurePath 与 Path 的核心差异

  • PurePath 无 I/O: 只能做路径字符串层面的操作,如拼接、拆分、比较等
  • Path 全功能: 在 PurePath 的基础上增加了文件系统访问能力
  • 实例化规则: 在 Windows 上运行 Path() 得到 WindowsPath,在 Linux 上得到 PosixPath
  • 使用建议: 日常开发中绝大多数场景直接用 Path 即可;仅在需要纯字符串层面处理路径且避免 I/O 开销时,才考虑使用 PurePath
# PurePath 主要用于路径字符串操作 from pathlib import PurePath, PurePosixPath, PureWindowsPath p = PurePosixPath("/usr/local/bin/python3") print(p.parent) # /usr/local/bin print(p.name) # python3 print(p.suffix) # 空(无扩展名) pw = PureWindowsPath("C:\\Users\\Admin\\Documents\\report.txt") print(pw.drive) # C: print(pw.parent) # C:\Users\Admin\Documents # PurePath 对象可以跨平台比较,即使运行在 Windows 上 PurePosixPath("/a/b") == PurePosixPath("/a/b") # True # Path 拥有 PurePath 的全部能力 + 文件 I/O from pathlib import Path p = Path("." ) print(p.exists()) # True(当前目录一定存在) print(p.is_dir()) # True print(p.absolute()) # 获取绝对路径,如 /home/user/project

简而言之,PurePath 是路径的"语法层面"抽象,Path 是路径的"语义+语法"抽象。如果你只需要操作路径字符串而不需要访问文件系统(比如在配置解析、URL 路径处理中),PurePath 更加轻量;否则直接使用 Path 即可。

三、路径创建与拼接

3.1 创建 Path 对象

Path 对象的创建方式非常灵活,支持字符串、多个路径片段组合、以及与其他 Path 对象组合:

from pathlib import Path # 方式一:从字符串创建 p1 = Path("/etc/config/app.ini") # 方式二:从多个片段创建 p2 = Path("/etc", "config", "app.ini") # 方式三:从当前目录创建 p3 = Path(".") # 相对路径 p4 = Path.cwd() # 当前工作目录的绝对路径 p5 = Path.home() # 用户家目录 # 方式四:空参数表示当前目录 p6 = Path() # 等价于 Path(".")

3.2 使用 / 运算符拼接路径

这是 pathlib 最令人喜爱的一个特性——重载 / 运算符用于路径拼接,代码书写就像在终端中使用 cd 命令一样自然:

from pathlib import Path base = Path("/home/user") # 使用 / 拼接路径(最推荐的方式) docs = base / "Documents" / "projects" print(docs) # /home/user/Documents/projects # / 运算符可以组合 Path 对象和字符串 sub = Path("subdir") file = base / sub / "file.txt" print(file) # /home/user/subdir/file.txt # 连续拼接 deep = base / "a" / "b" / "c" / "d" / "file.md" print(deep) # /home/user/a/b/c/d/file.md

3.3 使用 joinpath 拼接

joinpath() 方法提供了一种函数式调用的拼接方式,适合参数动态传入的场景:

from pathlib import Path base = Path("/data") # joinpath 可以接受多个参数 path = base.joinpath("2025", "05", "logs", "access.log") print(path) # /data/2025/05/logs/access.log # 动态拼接——当目录层级不确定时特别有用 parts = ["archive", "images", "photos", "vacation.jpg"] full_path = Path("/home").joinpath(*parts) print(full_path) # /home/archive/images/photos/vacation.jpg

3.4 相对路径与绝对路径的拼接规则

当拼接路径时,如果右侧的路径片段以根目录开头(如 /etc),它会重置左侧的基础路径:

from pathlib import Path base = Path("/home/user/projects") # 正常拼接 p1 = base / "src" print(p1) # /home/user/projects/src # 右侧以 / 开头时,左侧被替换(注意这个行为!) p2 = base / "/etc" print(p2) # /etc (/home/user/projects 被丢弃) # 使用 resolve() 可以获取规范化的绝对路径 relative = Path("../docs") p3 = base / relative print(p3.resolve()) # /home/user/docs

注意

当使用 / 运算符拼接路径时,如果右侧字符串以 / 开头(在 POSIX 上)或包含盘符(在 Windows 上),左侧的基础路径将被完全替换。这是 PurePath 的路径语义决定的,在使用动态输入拼接路径时需要特别注意。

四、路径属性

Path 对象提供了丰富的属性来获取路径的不同组成部分,远比 os.path 的字符串拆分操作要方便:

from pathlib import Path p = Path("/home/user/projects/hello_world.py") print("name :", p.name) # hello_world.py —— 完整文件名 print("stem :", p.stem) # hello_world —— 文件名(不含后缀) print("suffix:", p.suffix) # .py —— 文件后缀(含点) print("parent:", p.parent) # /home/user/projects —— 父目录 # suffixes 处理多后缀文件(如 .tar.gz) p2 = Path("archive.tar.gz") print(p2.suffixes) # ['.tar', '.gz'] —— 后缀列表 print(p2.stem) # archive —— 去除所有后缀 # parts 以元组形式返回路径的每一级 print(p.parts) # ('/', 'home', 'user', 'projects', 'hello_world.py') # drive 和 root(Windows 下特别有用) pw = Path("C:\\Users\\Admin\\file.txt") print(pw.drive) # C: print(pw.root) # \ print(pw.anchor) # C:\ —— drive + root 的组合

路径属性速查表

属性 返回 示例(对 /home/user/file.txt)
name 完整文件名 file.txt
stem 不含后缀的文件名 file
suffix 文件扩展名(含点) .txt
suffixes 多后缀列表 ['.tar', '.gz']
parent 父目录 Path /home/user
parents 所有父目录的可迭代对象 [Path('/home/user'), Path('/home'), Path('/')]
parts 各级路径元组 ('/', 'home', 'user', 'file.txt')
drive 盘符(仅Windows) C:
root 根目录分隔符 /\
anchor 路径锚点(drive+root) C:\

parents 属性是一个特殊的可迭代对象,可以像 parent 的链式调用一样逐级向上访问父目录,但更加简洁:

from pathlib import Path p = Path("/a/b/c/d/file.txt") # 逐级向上 print(p.parent) # /a/b/c/d print(p.parent.parent) # /a/b/c print(p.parent.parent.parent) # /a/b # 使用 parents 索引更加简洁 print(p.parents[0]) # /a/b/c/d print(p.parents[1]) # /a/b/c print(p.parents[2]) # /a/b print(p.parents[3]) # /a print(p.parents[4]) # / # 遍历所有父目录 for parent in p.parents: print(parent) # /a/b/c/d # /a/b/c # /a/b # /a # /

在日常开发中,nameparent 是最常用的两个属性,stemsuffix 在需要分离文件名和扩展名时非常方便,比传统 os.path.splitext() 更加直观。

五、文件操作

pathlib 将文件的常见读写操作直接封装在 Path 对象上,无需额外使用 open() 内置函数。以下是核心文件操作方法:

5.1 读取文件

from pathlib import Path p = Path("notes.txt") # 读取全部文本(自动处理编码) text = p.read_text(encoding="utf-8") print(text) # 读取全部字节 data = p.read_bytes() print(len(data)) # 文件字节数 # 逐行读取(使用 open() 上下文管理器) with p.open("r", encoding="utf-8") as f: for line in f: print(line.strip())

5.2 写入文件

from pathlib import Path p = Path("output.txt") # 写入文本(覆盖模式,自动创建父目录吗?不!) p.write_text("Hello, pathlib!\n第二行内容。\n", encoding="utf-8") # 以追加模式写入(需要使用 open) with p.open("a", encoding="utf-8") as f: f.write("追加的内容\n") # 写入二进制数据 p2 = Path("data.bin") p2.write_bytes(b"\x00\x01\x02\x03\xff") # 写文件前确保父目录存在 target = Path("subdir/nested/file.txt") target.parent.mkdir(parents=True, exist_ok=True) target.write_text("Content")

重要提醒

  • write_text()write_bytes() 不会自动创建父目录,写入前需要手动调用 parent.mkdir(parents=True, exist_ok=True)
  • write_text() 默认使用系统编码,显式指定 encoding="utf-8" 是最佳实践
  • 这两个方法都是覆盖写入,文件原有内容会被清空

5.3 重命名与删除

from pathlib import Path p = Path("old_name.txt") # rename —— 重命名文件或目录 p.rename("new_name.txt") # 也可以移动到其他目录(类似 mv 命令) p.rename(Path("/backup/old_name.txt")) # unlink —— 删除文件(不能用于目录) file = Path("temp.txt") file.unlink() # 删除文件 file.unlink(missing_ok=True) # 文件不存在时不报错(Python 3.8+) # rmdir —— 删除空目录(目录非空则会抛出 OSError) empty_dir = Path("empty_folder") empty_dir.rmdir() # 删除非空目录 —— 需要使用 shutil 模块 import shutil shutil.rmtree(Path("non_empty_folder"))

5.4 创建目录

from pathlib import Path # mkdir —— 创建目录 Path("new_folder").mkdir() # 创建单个目录 Path("a/b/c/d").mkdir(parents=True) # 递归创建不存在的父目录 Path("existing").mkdir(exist_ok=True) # 目录已存在时不报错 Path("a/b/c").mkdir(parents=True, exist_ok=True) # 常见组合 # touch —— 创建空文件(类似 Linux touch 命令) Path("new_file.txt").touch() # 创建空文件 Path("existing.txt").touch(exist_ok=True) # 文件已存在时更新修改时间而非报错

六、目录遍历

目录遍历是文件系统操作中最常见的需求之一。pathlib 提供了多个层级的方法来满足不同粒度的遍历需求。

6.1 iterdir —— 遍历直接子项

iterdir() 返回一个生成器,逐个产生当前目录下的所有直接子项(不递归),每个子项都是一个 Path 对象:

from pathlib import Path data_dir = Path("./data") for item in data_dir.iterdir(): if item.is_file(): print(f"[文件] {item.name} (大小: {item.stat().st_size} 字节)") elif item.is_dir(): print(f"[目录] {item.name}") # 使用列表推导式快速分类 files = [f for f in data_dir.iterdir() if f.is_file()] dirs = [d for d in data_dir.iterdir() if d.is_dir()]

6.2 glob —— 模式匹配

glob() 使用 Unix shell 风格的模式匹配来筛选文件,只搜索当前目录的直接子项(不递归):

from pathlib import Path base = Path("./project") # 查找所有 .py 文件 for py in base.glob("*.py"): print(py) # 查找以 "test_" 开头的文件 tests = base.glob("test_*") # glob 支持单层子目录模式匹配(但不是递归) configs = base.glob("*/config.yaml") # 统计某类型文件数量 img_count = len(list(base.glob("*.png"))) print(f"找到 {img_count} 个 PNG 文件")

6.3 rglob —— 递归模式匹配

rglob()glob() 的递归版本,搜索所有子目录(深度不限)。这是最常用的目录遍历方法之一,特别适合于查找项目中所有满足条件的文件:

from pathlib import Path base = Path("./project") # 递归查找所有 .py 文件(无论嵌套多深) for py in base.rglob("*.py"): print(py) # 查找所有 __init__.py 文件 init_files = list(base.rglob("__init__.py")) print(f"找到 {len(init_files)} 个 __init__.py") # 查找所有包含 "test" 的目录 test_dirs = [d for d in base.rglob("*test*") if d.is_dir()] # 使用 ** 在 glob 中表达递归(效果与 rglob 相同) # 注意:glob("**/*.py") 和 rglob("*.py") 等价 py_files_1 = list(base.glob("**/*.py")) py_files_2 = list(base.rglob("*.py")) print(py_files_1 == py_files_2) # True # 进阶:排除某些模式 # 查找所有 .txt 文件但排除在 node_modules 中的 for txt in base.rglob("*.txt"): if "node_modules" not in txt.parts: print(txt)

6.4 walk —— Python 3.12+ 的新方法

Python 3.12 为 Path 增加了 walk() 方法,功能类似于 os.walk(),但返回的是 Path 对象,使用更加方便。它按自顶向下或自底向上的顺序遍历目录树:

from pathlib import Path base = Path("./project") # walk() 返回三元组 (当前目录, 子目录列表, 文件列表) for root, dirs, files in base.walk(): print(f"目录: {root}") print(f" 子目录: {', '.join(d.name for d in dirs)}") print(f" 文件数: {len(files)}") # top_down=False 表示自底向上遍历 for root, dirs, files in base.walk(top_down=False): # 自底向上时,可以先删除文件再删除目录 for f in files: f.unlink() root.rmdir() # 目录已空,可以删除 # walk() vs rglob() 的选择: # - 需要同时处理目录和文件时 → walk() # - 只需要匹配特定模式的文件时 → rglob()

遍历方法的选择指南

  • iterdir(): 只需要当前目录的直接子项,不需要筛选
  • glob(): 需要当前目录下匹配特定模式的文件(不递归)
  • rglob(): 需要递归查找所有子目录中匹配特定模式的文件(最常用)
  • walk(): Python 3.12+,需要同时访问目录和文件的完整信息,控制遍历方向

七、文件信息与元数据

Path 对象通过 stat() 方法获取文件的详细元数据,该方法返回 os.stat_result 对象:

from pathlib import Path import os import stat import time p = Path("example.py") st = p.stat() print("文件大小:", st.st_size, "字节") print("最后修改时间:", time.ctime(st.st_mtime)) print("最后访问时间:", time.ctime(st.st_atime)) print("创建时间:", time.ctime(st.st_ctime)) print("文件权限:", oct(st.st_mode)) print("inode编号:", st.st_ino) # 判断文件类型(基于 stat 结果) if stat.S_ISREG(st.st_mode): print("这是普通文件") elif stat.S_ISDIR(st.st_mode): print("这是目录") elif stat.S_ISLNK(st.st_mode): print("这是符号链接")

便捷的路径检查方法

from pathlib import Path p = Path("some_path") p.exists() # 路径是否存在 p.is_file() # 是否是文件(且存在) p.is_dir() # 是否是目录(且存在) p.is_symlink() # 是否是符号链接 p.is_socket() # 是否是 socket 文件 p.is_fifo() # 是否是 FIFO(命名管道) p.is_block_device() # 是否是块设备 p.is_char_device() # 是否是字符设备 p.is_mount() # 是否是挂载点(Python 3.7+) # stat 的快捷方法 p.stat().st_size # 文件大小(字节) p.lstat().st_size # 如果是符号链接,获取链接本身的元数据而非目标

owner 和 group —— 查询文件所有者

Path 还提供了两个跨平台的方法来查询文件的所有者和所属组(在 Windows 上返回用户名和域名):

from pathlib import Path p = Path("/etc/hosts") print("所有者:", p.owner()) # root(POSIX) print("所属组:", p.group()) # root(POSIX) # lchmod —— 修改符号链接的权限(而非目标文件) # chmod —— 修改文件权限 p.chmod(0o644) # rw-r--r--

八、路径解析与转换

在实际开发中,我们经常需要在相对路径和绝对路径之间转换,或者计算两个路径之间的相对关系。pathlib 提供了清晰的 API 来完成这些任务。

8.1 resolve —— 解析为规范化的绝对路径

resolve() 将路径解析为绝对路径,并自动处理 ... 以及符号链接:

from pathlib import Path # 相对路径转绝对路径 rel = Path("../docs/./guide/../api/config.yaml") abs_path = rel.resolve() print(abs_path) # 如 /home/user/projects/api/config.yaml # resolve() 还可以解析符号链接 link = Path("/usr/bin/python3") # 假设这是符号链接 real = link.resolve() print(real) # 如 /usr/bin/python3.10(符号链接的目标真实路径)

8.2 absolute —— 获取绝对路径(不解析符号链接)

absolute() 仅将相对路径改为绝对路径,不会展开 ...,也不会解析符号链接:

from pathlib import Path rel = Path("../docs/config.yaml") abs_path = rel.absolute() print(abs_path) # 如 /home/user/projects/../docs/config.yaml # 注意:absolute() 保留了 ..,而 resolve() 会去掉它 # absolute() 和 resolve() 的差异 p = Path("./subdir/../file.txt") print(p.absolute()) # /home/user/subdir/../file.txt (不规范化) print(p.resolve()) # /home/user/file.txt (规范化)

absolute() vs resolve()

  • absolute(): 仅在路径前拼接当前工作目录,不做任何规范化处理,不访问文件系统,不会失败
  • resolve(): 将路径规范化为标准绝对路径(去除 ...),解析符号链接,要求路径存在(否则在某些系统上可能会失败或返回非预期结果)

8.3 relative_to —— 计算相对路径

relative_to() 计算从一个路径到另一个路径的相对关系,相当于 os.path.relpath() 的 pathlib 版本:

from pathlib import Path p = Path("/home/user/projects/src/main.py") # 相对于某个基准路径 rel = p.relative_to("/home/user/projects") print(rel) # src/main.py # 在项目目录结构中非常有用 project_root = Path("/home/user/myapp") file_path = project_root / "src/utils/helper.py" module_path = file_path.relative_to(project_root) module_name = ".".join(module_path.with_suffix("").parts) print(module_name) # src.utils.helper (可用于动态 import) # 如果路径不在基准路径下,会抛出 ValueError try: p.relative_to("/other/path") except ValueError as e: print(e) # '...' does not start with '...'

8.4 路径类型转换与校验

from pathlib import Path, PurePosixPath, PureWindowsPath # Path ↔ 字符串 p = Path("/data/file.txt") s = str(p) # "/data/file.txt" p2 = Path(s) # Path("/data/file.txt") # 跨平台路径转换 posix = PurePosixPath("/home/user/file.txt") win = PureWindowsPath("C:\\Users\\Admin\\file.txt") # as_posix —— 将 Windows 路径转为 POSIX 风格(字符串) print(win.as_posix()) # C:/Users/Admin/file.txt # as_uri —— 将绝对路径转为 file:// URI print(p.as_uri()) # file:///data/file.txt # with_name / with_stem / with_suffix —— 替换路径的组成部分 p = Path("/data/report.txt") print(p.with_name("summary.txt")) # /data/summary.txt print(p.with_stem("summary")) # /data/summary.txt (Python 3.9+) print(p.with_suffix(".md")) # /data/report.md # 文件后缀替换的常见用法:日志轮转 log_path = Path("app.log") archive = log_path.with_suffix(".log.1") print(archive) # app.log.1 # 注意:with_suffix 会替换最后一个后缀

九、Path vs os.path 深度对比

对于有 Python 3 开发经验的开发者,了解 pathlibos.path 之间的对应关系,可以帮助高效迁移旧代码。以下是常用操作的全面对照表:

功能 os.path / os 方式 pathlib 方式
当前目录 os.getcwd() Path.cwd()
用户目录 os.path.expanduser("~") Path.home()
路径拼接 os.path.join(a, b) Path(a) / bPath(a).joinpath(b)
路径存在 os.path.exists(p) Path(p).exists()
是否是文件 os.path.isfile(p) Path(p).is_file()
是否是目录 os.path.isdir(p) Path(p).is_dir()
文件名 os.path.basename(p) Path(p).name
父目录 os.path.dirname(p) Path(p).parent
文件名无后缀 os.path.splitext(os.path.basename(p))[0] Path(p).stem
文件后缀 os.path.splitext(p)[1] Path(p).suffix
绝对路径 os.path.abspath(p) Path(p).resolve()
相对路径 os.path.relpath(p, start) Path(p).relative_to(start)
拆分路径 os.path.split(p) Path(p).parent, Path(p).name
创建目录 os.makedirs(d, exist_ok=True) Path(d).mkdir(parents=True, exist_ok=True)
读取文本 open(p).read() Path(p).read_text()
写入文本 open(p, "w").write(s) Path(p).write_text(s)
删除文件 os.remove(p) Path(p).unlink()
重命名 os.rename(a, b) Path(a).rename(b)
文件大小 os.path.getsize(p) Path(p).stat().st_size
修改时间 os.path.getmtime(p) Path(p).stat().st_mtime
列表目录 os.listdir(d) Path(d).iterdir()
模式匹配 glob.glob("**/*.py") Path().rglob("*.py")
环境变量展开 os.path.expandvars(s) PurePath 不支持,需结合 os.path.expandvars

迁移建议

  1. 新项目直接使用 pathlib: 所有涉及路径操作的新代码都应优先使用 pathlib
  2. 旧项目逐步替换:os.path.join 和文件读写部分开始,逐步替换为 pathlib 风格
  3. 混合使用无问题: Path 对象可以传给 os 模块的函数(Python 3.6+),也可以被 str() 转换回字符串,过渡期间可以混合使用
  4. 性能差异: pathlib 作为纯 Python 实现,在极高频调用的场景下(如每秒数万次操作)可能比 C 语言实现的 os.path 稍慢,但对于绝大多数应用此差异可以忽略

十、实际应用场景

场景一:项目配置路径管理

from pathlib import Path class ProjectPaths: """项目路径管理器""" def __init__(self, root: str | Path): self.root = Path(root).resolve() self.src = self.root / "src" self.tests = self.root / "tests" self.data = self.root / "data" self.logs = self.root / "logs" def ensure_dirs(self): """确保所有必需的目录存在""" for d in [self.src, self.tests, self.data, self.logs]: d.mkdir(parents=True, exist_ok=True) def find_configs(self): """递归查找所有 .yaml 和 .json 配置文件""" configs = list(self.src.rglob("*.yaml")) configs.extend(self.src.rglob("*.json")) return configs def log_path(self, name: str) -> Path: """生成日志文件路径(自动添加日期)""" from datetime import date today = date.today().isoformat() return self.logs / f"{today}_{name}.log" # 使用示例 paths = ProjectPaths("/home/user/myapp") paths.ensure_dirs() print(paths.find_configs()) log_file = paths.log_path("worker") log_file.write_text("进程启动\n", encoding="utf-8")

场景二:批量重命名文件

from pathlib import Path def rename_files(directory: str, prefix: str, ext: str): """批量重命名指定扩展名的文件""" dir_path = Path(directory) for i, file in enumerate(dir_path.glob(f"*.{ext}"), 1): new_name = f"{prefix}_{i:03d}.{ext}" file.rename(file.parent / new_name) print(f"重命名: {file.name} → {new_name}") # rename_files("downloads", "photo", "jpg")

场景三:文件系统监控辅助

from pathlib import Path import time def find_recently_modified(directory: str, minutes: int = 60) -> list[Path]: """查找指定时间内修改过的文件""" cutoff = time.time() - minutes * 60 dir_path = Path(directory) recent = [] for f in dir_path.rglob("*"): if f.is_file() and f.stat().st_mtime > cutoff: recent.append(f) return sorted(recent, key=lambda x: x.stat().st_mtime, reverse=True) # 获取最近 1 小时内修改过的文件 print(find_recently_modified(".", minutes=60))

十一、核心要点总结

十二、进一步思考与练习

实践练习

  1. 文件分类器: 编写一个脚本,使用 Path 遍历某个目录,按文件扩展名将文件分类到不同的子目录中(如 .jpg/.png → images/.mp3/.wav → audio/
  2. 日志清理工具: 使用 Path.stat().st_mtime 查找并删除指定目录中超过 N 天未修改的日志文件
  3. 项目脚手架: 编写一个函数,接收项目名称和目录结构描述(嵌套字典),自动创建完整的项目目录树和必要的 __init__.py 文件
  4. 重复文件查找器: 使用 rglob() 遍历目录树,通过文件名和文件大小检测可能的重复文件
  5. 路径表达式解析: 使用 PurePathparts 属性,实现一个函数将文件系统路径转换为 Python 模块导入路径

补充阅读建议

  • 官方文档: Python pathlib 模块文档 — 权威参考
  • PEP 428: pathlib 模块的最初设计提案,了解设计思路和取舍
  • Python 3.12 更新: 关注 Path.walk()pathlib.Path. 相关的 changelog