← 返回Python标准库精讲目录
← 返回学习笔记首页
专题: Python标准库精讲系统学习
关键词: Python, 标准库, pathlib, Path, PurePath, 文件路径, 目录操作, 文件操作, os.path
一、pathlib模块概述
pathlib是Python 3.4版本引入的面向对象文件路径操作模块,旨在提供一个更加直观、可读性更强的路径操作接口。与传统的os.path模块相比,pathlib将路径抽象为对象,通过方法调用和运算符重载完成路径操作,代码更加简洁优雅。
pathlib的核心设计理念是将文件系统路径视为"对象"而非"字符串"。这意味着路径拼接、分解、比较等操作不再依赖字符串处理函数,而是通过对象方法和运算符来完成,大大减少了字符串解析带来的错误风险。
与os.path的对比
操作类型
os.path方式
pathlib方式
路径拼接
os.path.join(dir, file)
Path(dir) / file
获取文件名
os.path.basename(path)
Path(path).name
获取父目录
os.path.dirname(path)
Path(path).parent
判断是否存在
os.path.exists(path)
Path(path).exists()
遍历目录
os.listdir(dir)
Path(dir).iterdir()
pathlib的两大核心类是PurePath(纯路径处理)和Path(具体路径操作)。PurePath只做路径的解析和运算,不涉及实际的I/O操作;Path继承PurePath并增加了所有与文件系统交互的方法。这种分离设计使得PurePath可以在没有文件系统的场景下安全使用(如URL路径处理)。
核心优势: 面向对象设计替代字符串拼接、运算符/重载实现直观路径组合、统一的文件操作API、跨平台路径自动适配、与os.path兼容且用法更现代。
# pathlib vs os.path 对比示例
from pathlib import Path
import os.path
# 传统方式
path1 = os.path.join("/home/user", "docs", "readme.txt")
base = os.path.basename(path1) # "readme.txt"
ext = os.path.splitext(path1)[1] # ".txt"
# pathlib方式
p = Path("/home/user") / "docs" / "readme.txt"
base = p.name # "readme.txt"
ext = p.suffix # ".txt"
print(f"pathlib方式更直观: {p}")
print(f"传统方式结果: {path1}")
二、PurePath纯路径处理
PurePath是pathlib中的路径解析基类,只进行纯字符串层面的路径操作,不访问实际文件系统。它有两个具体子类:PurePosixPath(POSIX风格路径,如Linux/macOS)和PureWindowsPath(Windows风格路径)。
PurePath的自动适配与显式使用
当直接使用PurePath()构造时,会自动适配当前操作系统的路径格式。如果需要跨平台路径分析(如在Windows上分析Linux路径),则应显式使用PurePosixPath或PureWindowsPath。
# PurePath基本用法
from pathlib import PurePath, PurePosixPath, PureWindowsPath
# 自动适应当前系统
p = PurePath("/home/user/docs/file.txt")
print(p) # PurePosixPath('/home/user/docs/file.txt') 在Linux上
# 显式指定路径风格
posix_p = PurePosixPath("/home/user/docs/file.txt")
win_p = PureWindowsPath("C:\\Users\\Admin\\docs\\file.txt")
print(posix_p)
print(win_p)
路径拼接与运算符/
pathlib使用/运算符实现路径拼接,这是最引人注目的特性之一。左操作数必须是PurePath(或Path)对象,右操作数可以是字符串或另一个Path对象。多个路径段可以链式拼接。
# 路径拼接示例
from pathlib import PurePosixPath
base = PurePosixPath("/home/user")
# 单个段拼接
docs = base / "docs"
# 链式拼接
full = base / "docs" / "python" / "notes.txt"
print(full) # PurePosixPath('/home/user/docs/python/notes.txt')
# 右操作数也可以是Path对象
sub = PurePosixPath("projects")
result = base / sub / "src/main.py"
print(result) # PurePosixPath('/home/user/projects/src/main.py')
# 斜杠开头的字符串会重置路径
p2 = PurePosixPath("user") / "/etc" / "config"
print(p2) # PurePosixPath('/etc/config') — 注意/user被丢弃了
路径分解属性
PurePath提供了一系列属性来分解路径的各个组成部分,理解这些属性对于精准的路径操作非常重要。
属性 说明 示例结果
drive 盘符(Windows)或空 'C:' / ''
root 根目录标记 '\\' / '/'
anchor drive + root 'C:\\' / '/'
parts 逐级拆分的元组 ('/', 'home', 'user', 'docs')
parent 直接父路径 PurePosixPath('/home/user')
parents 所有父路径的可迭代对象 [PurePosixPath('/home'), ...]
name 末尾文件名/目录名 'file.txt'
stem 不含后缀的文件名 'file'
suffix 扩展名(含点) '.txt'
suffixes 所有扩展名列表 ['.tar', '.gz']
# 路径分解实战
from pathlib import PurePosixPath
p = PurePosixPath("/home/user/docs/python/notes.txt")
print(f"完整路径: {p}")
print(f"drive: {p.drive!r}") # ''(POSIX无盘符概念)
print(f"root: {p.root!r}") # '/'
print(f"anchor: {p.anchor!r}") # '/'
print(f"parts: {p.parts}") # ('/', 'home', 'user', 'docs', 'python', 'notes.txt')
print(f"parent: {p.parent}") # /home/user/docs/python
print(f"name: {p.name}") # notes.txt
print(f"stem: {p.stem}") # notes
print(f"suffix: {p.suffix}") # .txt
# parents — 逐级上溯
for i, parent in enumerate(p.parents):
print(f"parents[{i}]: {parent}")
# parents[0]: /home/user/docs/python
# parents[1]: /home/user/docs
# parents[2]: /home/user
# parents[3]: /home
# parents[4]: /
# 多后缀文件
tgz = PurePosixPath("archive.tar.gz")
print(tgz.suffix) # .gz
print(tgz.suffixes) # ['.tar', '.gz']
print(tgz.stem) # archive.tar
特别注意: PurePath不接触文件系统,因此exists()、is_dir()、is_file()等方法在PurePath上不可用——这些是在Path类中实现的。如果只需要解析和操作路径字符串(如URL、配置文件中的路径),应优先使用PurePath以获得更好的性能和安全性。
三、Path核心类
Path继承了PurePath的全部功能,并增加了所有涉及实际文件系统交互的方法。它是日常开发中使用最多的类,封装了文件测试、目录遍历、元信息查询等操作。
构造常用路径
Path提供了多个类方法来快速获取系统级和用户相关的重要路径,大幅简化了路径定位的代码量。
# Path的构造与常用类方法
from pathlib import Path
# 基于当前工作目录
p1 = Path(".") # 当前目录
p2 = Path("docs/readme.txt")
# 绝对路径
p3 = Path("/usr/local/bin")
p4 = Path.home() # 用户家目录, 如 /home/user 或 C:\Users\xxx
p5 = Path.cwd() # 当前工作目录
print(f"家目录: {p4}")
print(f"当前目录: {p5}")
# 混合构造
config = Path.home() / ".config" / "myapp" / "config.json"
print(f"配置文件路径: {config}")
文件系统查询
Path提供了丰富的文件系统状态查询方法,用于判断路径类型、获取元信息和测试文件状态,是编写健壮文件操作代码的基础。
# 文件状态查询
from pathlib import Path
import time
p = Path("/etc/hostname")
# 存在性检查
print(f"是否存在: {p.exists()}")
# 类型判断
print(f"是目录吗: {p.is_dir()}")
print(f"是文件吗: {p.is_file()}")
print(f"是符号链接: {p.is_symlink()}")
print(f"是绝对路径: {p.is_absolute()}")
# 文件元信息 (stat)
if p.exists():
stat_info = p.stat()
print(f"文件大小: {stat_info.st_size} bytes")
print(f"最后修改: {time.ctime(stat_info.st_mtime)}")
print(f"权限模式: {oct(stat_info.st_mode)}")
print(f"inode: {stat_info.st_ino}")
目录遍历与文件筛选
Path的目录遍历功能非常强大,尤其是glob模式匹配,可以快速筛选出符合特定模式的文件和目录。itertools风格链式调用让复杂筛选变得简单。
# 目录遍历
from pathlib import Path
data_dir = Path("data")
# iterdir() — 遍历直接子项(非递归)
if data_dir.exists():
for entry in data_dir.iterdir():
kind = "目录" if entry.is_dir() else "文件"
print(f"[{kind}] {entry.name}")
# glob() — 模式匹配(非递归)
for py_file in Path("src").glob("*.py"):
print(f"Python文件: {py_file}")
# rglob() — 递归全匹配
for all_py in Path("project").rglob("**/*.py"):
print(f"找到: {all_py}")
# 注意: rglob("*.py") 等价于 glob("**/*.py")
for test_file in Path("tests").rglob("test_*.py"):
print(f"测试文件: {test_file}")
# 组合筛选
img_dir = Path("assets")
images = [f for f in img_dir.rglob("*") if f.suffix.lower() in (".png", ".jpg", ".jpeg", ".gif")]
print(f"找到 {len(images)} 个图片文件")
性能提示: glob模式比手动os.listdir+fnmatch高效且简洁。对于需要递归搜索的场景,rglob()是最佳选择。如果同时需要文件元信息(大小、修改时间),建议使用Path.stat()而非多次访问文件系统。
四、路径操作
Path类提供了完整的目录和文件操作功能,包括创建、删除、重命名和链接操作。这些方法通常会引发OSError或FileNotFoundError等异常,建议在调用时做好异常处理。
目录创建与删除
mkdir用于创建目录,rmdir用于删除空目录。mkdir的parents和exist_ok参数提供了类似mkdir -p的行为,大幅简化了多级目录创建逻辑。
# 目录操作
from pathlib import Path
# 创建单级目录
Path("temp").mkdir(exist_ok=True)
# 创建多级目录 (类似 mkdir -p)
Path("project/src/main/java/com/example").mkdir(parents=True, exist_ok=True)
# 删除空目录
Path("temp").rmdir() # 目录必须为空,否则抛出OSError
# 删除目录树(需要shutil配合)
import shutil
shutil.rmtree("project") # 递归删除非空目录
文件重命名与替换
rename直接重命名文件或目录,replace则会在目标已存在时强制覆盖,避免了跨设备操作时的复杂性。
# 文件重命名与替换
from pathlib import Path
# 重命名(同设备内移动)
Path("temp.txt").rename("temp_backup.txt")
# 跨设备移动(Python 3.8+)
# Path("source.txt").rename("/tmp/source.txt") # 可能跨设备
# replace — 替换目标文件(无论是否存在)
Path("new_version.txt").replace("production.txt")
# 安全重命名(先检查目标是否存在)
def safe_rename(src: Path, dst: Path):
if dst.exists():
backup = dst.with_suffix(dst.suffix + ".bak")
dst.rename(backup)
print(f"已备份旧文件为: {backup}")
src.rename(dst)
safe_rename(Path("draft.txt"), Path("final.txt"))
删除与链接
unlink用于删除文件,symlink_to和hardlink_to分别创建符号链接和硬链接。链接操作在跨平台时需要特别注意——Windows上可能需要管理员权限。
# 文件删除与链接
from pathlib import Path
# 删除文件
file = Path("temp_backup.txt")
if file.exists():
file.unlink() # 删除文件,missing_ok=True可抑制FileNotFoundError
# Python 3.8+: file.unlink(missing_ok=True)
# 创建符号链接
target = Path("/usr/local/bin/python3")
link = Path("~/mypython").expanduser()
# link.symlink_to(target) # 需要合适权限
# 创建硬链接
original = Path("important.txt")
hardlink = Path("important_backup.txt")
if original.exists():
# hardlink.hardlink_to(original) # Windows上可能需要管理员权限
print(f"将为 {original} 创建硬链接")
# with_name / with_suffix — 派生新路径而不访问磁盘
p = Path("data/report_2024.csv")
print(p.with_name("report_2025.csv")) # data/report_2025.csv
print(p.with_suffix(".json")) # data/report_2024.json
安全实践: 在进行文件删除/移动操作前,先检查文件是否存在,或使用Pyhhon 3.8+的missing_ok参数。rename和replace操作在Windows上如果目标已存在可能会失败,建议先unlink再rename,或使用replace方法。
五、文件读写
Path内置了简洁的文件读写方法,支持纯文本和二进制模式的读写操作,无需手动管理文件打开和关闭。对于简单的文件读写场景,这些方法比内置的open()更加便捷。
文本文件读写
read_text一次性读取整个文本文件的内容并返回字符串;write_text将字符串写入文件。这两个方法会自动处理文件的打开和关闭,适合中等规模的文件读写。
# 文本文件读写
from pathlib import Path
file = Path("notes.txt")
# 写入文本(覆盖模式)
file.write_text("这是第一行\n")
file.write_text("这是第二行\n") # 注意:会覆盖上一行!
# 追加写入
with file.open("a") as f:
f.write("这是追加的行\n")
# 读取全部文本
content = file.read_text(encoding="utf-8")
print(content)
# 逐行处理
for line in file.read_text().splitlines():
if line.strip():
print(f">> {line.strip()}")
二进制文件读写
read_bytes和write_bytes用于处理二进制文件,如图像、音频、压缩包等。它们以字节串(bytes)的形式操作数据,适用于任何非文本文件。
# 二进制文件读写
from pathlib import Path
# 写入二进制数据
data = b"\x89PNG\r\n\x1a\n" # PNG文件头
Path("icon.png").write_bytes(data)
# 读取二进制数据
img_data = Path("icon.png").read_bytes()
print(f"读取了 {len(img_data)} 字节")
print(f"前8个字节: {img_data[:8].hex()}")
# 复制文件(用二进制方式)
src = Path("source.docx")
dst = Path("backup.docx")
if src.exists():
dst.write_bytes(src.read_bytes())
print(f"已复制到 {dst}")
open()上下文管理器
对于需要精细控制(如指定编码、逐行处理、大文件分块读取)的场景,Path.open()提供了与内置open()相同的功能,但以方法调用的方式集成在Path对象上。
# 使用Path.open()上下文管理器
from pathlib import Path
log = Path("server.log")
# 逐行读取大文件(推荐方式)
with log.open("r", encoding="utf-8") as f:
for line in f:
if "ERROR" in line:
print(f"错误日志: {line.strip()}")
# 二进制模式打开
with Path("data.bin").open("rb") as f:
header = f.read(32)
print(f"文件头: {header.hex()}")
# 追加模式
with Path("access.log").open("a") as f:
import datetime
f.write(f"[{datetime.datetime.now()}] 访问记录\n")
# 文件锁配合(需额外库)
# with fasteners.InterProcessLock(Path("data.lock")):
# with Path("shared.json").open("r+") as f:
# data = json.load(f)
# data["counter"] = data.get("counter", 0) + 1
# f.seek(0)
# json.dump(data, f)
注意事项: read_text()和read_bytes()会将整个文件加载到内存中,不适合大文件(如数GB的日志)。对于大文件,应使用Path.open()配合for循环逐行处理。write_text()和write_bytes()是覆盖写入,如需追加应使用open("a")模式。
六、路径解析与转换
Path提供了丰富的路径解析和格式转换方法,用于将相对路径解析为绝对路径、计算相对路径、生成URI以及在不同路径风格之间转换。
resolve与absolute — 获取绝对路径
resolve解析符号链接并返回规范化的绝对路径;absolute仅将相对路径转换为绝对路径,不解析符号链接。理解两者的区别对于正确处理路径十分关键。
# 路径解析
from pathlib import Path
# resolve() — 消解.和..并解析符号链接
rel = Path("../docs/./notes.txt")
abs_path = rel.resolve()
print(f"相对路径: {rel}")
print(f"解析后: {abs_path}")
# absolute() — Python 3.11+ 仅转绝对路径,不解析符号链接
cur = Path(".")
if hasattr(cur, "absolute"):
print(f"当前绝对路径: {cur.absolute()}")
else:
print(f"回退方案: {cur.resolve()}")
relative_to — 计算相对路径
relative_to计算从某个基准路径到当前路径的相对路径表示,常用于需要在不同目录结构之间表达路径关系的场景。
# relative_to — 计算相对路径
from pathlib import Path
base = Path("/home/user/project/src")
target = Path("/home/user/project/src/utils/helper.py")
# 计算从base到target的相对路径
rel = target.relative_to(base)
print(rel) # PurePosixPath('utils/helper.py')
# 带基准目录部分匹配
# rel = target.relative_to("/home/user/project")
# print(rel) # src/utils/helper.py
# 如果路径不匹配会抛出ValueError
try:
target.relative_to("/var/log")
except ValueError as e:
print(f"路径不匹配: {e}")
# Python 3.12+ — walk_up参数允许沿目录树向上
# try:
# rel_up = target.relative_to("/home/user/project/shared", walk_up=True)
# print(rel_up) # '../src/utils/helper.py'
# except ValueError:
# pass
URI与POSIX风格转换
as_uri将文件路径转换为file:// URI格式(需绝对路径),这在Web开发中非常实用。as_posix将路径中的反斜杠统一转换为正斜杠,便于跨平台序列化。
# URI与格式转换
from pathlib import Path
from pathlib import PureWindowsPath
# as_uri — 生成file:// URI
abs_path = Path("/home/user/docs/report.pdf")
uri = abs_path.as_uri()
print(uri) # file:///home/user/docs/report.pdf
# Windows路径转URI
# win = PureWindowsPath("C:\\Users\\Admin\\report.pdf")
# print(win.as_uri()) # file:///C:/Users/Admin/report.pdf
# as_posix — 统一使用正斜杠
# win_path = PureWindowsPath("C:\\Users\\Admin")
# print(win_path.as_posix()) # C:/Users/Admin
# 路径比较
p1 = Path("/home/user/docs")
p2 = Path("/home/user/docs")
print(f"路径相等: {p1 == p2}") # True
# 判断子路径
config = Path("/etc/nginx/nginx.conf")
etc = Path("/etc")
try:
config.relative_to(etc)
print(f"{config} 在 {etc} 之下")
except ValueError:
print(f"不在同一路径下")
注意: relative_to要求目标路径必须是当前路径的前缀(包含关系),否则抛出ValueError。Python 3.12新增的walk_up参数支持生成包含..的相对路径。as_uri要求路径必须是绝对路径。
七、实战应用
将pathlib应用于实际开发场景可以大幅提升代码质量和开发效率。以下是几个高频实战场景的完整代码示例。
场景一:批量文件重命名
批量修改文件名(如统一添加前缀/后缀、替换特定字符、修改扩展名)是文件处理中最常见的需求。结合Path的iterdir/glob和with_stem/with_suffix方法,可以写出简洁的重命名逻辑。
# 批量重命名:给所有图片添加日期前缀
from pathlib import Path
import datetime
today = datetime.date.today().strftime("%Y%m%d")
img_dir = Path("gallery")
# 安全重命名函数
def batch_rename(directory: Path, pattern: str, prefix: str = ""):
"""为匹配pattern的文件添加prefix前缀"""
renamed = 0
for f in directory.glob(pattern):
new_name = f"{prefix}{f.stem}{f.suffix}"
new_path = f.with_name(new_name)
if not new_path.exists():
f.rename(new_path)
renamed += 1
print(f"重命名: {f.name} → {new_name}")
else:
print(f"跳过: {new_path.name} 已存在")
return renamed
if img_dir.exists():
count = batch_rename(img_dir, "*.jpg", f"{today}_")
print(f"已重命名 {count} 个文件")
# 替换文件名中的空格
def replace_spaces(directory: Path, replacement: str = "_"):
for f in directory.rglob("*"):
if f.is_file() and " " in f.stem:
new_name = f"{f.stem.replace(' ', replacement)}{f.suffix}"
f.rename(f.with_name(new_name))
replace_spaces(Path("documents"), "_")
场景二:目录树遍历与统计
遍历目录树获取文件类型分布、总大小、最新修改时间等统计信息,是自动化监控和报告生成的基础。
# 目录树统计分析
from pathlib import Path
from collections import defaultdict
import datetime
def analyze_directory(root: Path):
"""分析目录结构,返回统计信息"""
stats = {
"total_files": 0,
"total_dirs": 0,
"total_size": 0,
"by_extension": defaultdict(int),
"by_size_range": defaultdict(int),
"largest_files": [],
"newest_files": [],
}
for entry in root.rglob("*"):
if entry.is_dir():
stats["total_dirs"] += 1
elif entry.is_file():
stats["total_files"] += 1
size = entry.stat().st_size
stats["total_size"] += size
# 按扩展名分类
ext = entry.suffix.lower() or "(无扩展名)"
stats["by_extension"][ext] += 1
# 按大小范围分类
if size < 1024:
stats["by_size_range"]["<1KB"] += 1
elif size < 1024 * 1024:
stats["by_size_range"]["1KB-1MB"] += 1
else:
stats["by_size_range"][">1MB"] += 1
# 记录最大文件
stats["largest_files"].append((size, entry))
stats["newest_files"].append((entry.stat().st_mtime, entry))
# 排序
stats["largest_files"].sort(reverse=True, key=lambda x: x[0])
stats["newest_files"].sort(reverse=True, key=lambda x: x[0])
return stats
# 使用示例
project = Path("project")
if project.exists():
info = analyze_directory(project)
print(f"文件总数: {info['total_files']}")
print(f"目录总数: {info['total_dirs']}")
print(f"总大小: {info['total_size'] / 1024 / 1024:.2f} MB")
print(f"按扩展名统计: {dict(info['by_extension'])}")
if info["largest_files"]:
size, f = info["largest_files"][0]
print(f"最大文件: {f} ({size / 1024:.1f} KB)")
if info["newest_files"]:
mtime, f = info["newest_files"][0]
dt = datetime.datetime.fromtimestamp(mtime)
print(f"最新修改: {f} ({dt})")
场景三:文件类型筛选与分类整理
根据文件类型自动分类整理到不同目录,是文件管理的常用场景。结合suffix属性、shutil.move和异常处理,可以构建健壮的文件整理工具。
# 文件类型筛选与自动分类
from pathlib import Path
import shutil
# 按类别整理文件
FILE_CATEGORIES = {
"images": [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".svg", ".webp"],
"documents": [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md"],
"archives": [".zip", ".tar", ".gz", ".bz2", ".7z", ".rar"],
"code": [".py", ".js", ".ts", ".java", ".cpp", ".h", ".css", ".html", ".json", ".yaml"],
"videos": [".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv"],
}
def organize_files(download_dir: Path):
"""将下载目录中的文件按类型整理到子目录"""
if not download_dir.exists():
print(f"目录不存在: {download_dir}")
return
for f in download_dir.iterdir():
if not f.is_file():
continue
# 判断文件类别
target_category = "others"
for category, extensions in FILE_CATEGORIES.items():
if f.suffix.lower() in extensions:
target_category = category
break
# 创建分类目录并移动文件
target_dir = download_dir / target_category
target_dir.mkdir(exist_ok=True)
target_path = target_dir / f.name
if not target_path.exists():
shutil.move(str(f), str(target_path))
print(f"移动: {f.name} → {target_category}/")
else:
print(f"跳过: {f.name} (目标已存在)")
# 统计结果
for category in list(FILE_CATEGORIES.keys()) + ["others"]:
cat_dir = download_dir / category
if cat_dir.exists():
count = len(list(cat_dir.iterdir()))
print(f" {category}: {count} 个文件")
# 使用
# organize_files(Path.home() / "Downloads")
生产环境建议: 使用pathlib重写遗留的os.path代码。在实际项目中,pathlib代码的平均行数比os.path版本少30%-50%,可读性显著提升。结合类型注解(如Path -> Path类型提示),还能获得IDE的自动补全和类型检查支持。
八、核心总结
pathlib模块是Python面向对象路径操作的里程碑式设计,它从根本上改变了Python开发者操作文件系统的方式。
核心要点:
1. PurePath系列 :纯路径解析,不访问文件系统,适合路径字符串运算和跨平台分析。
2. Path系列 :继承PurePath,集成所有文件I/O操作,是日常开发的主力类。
3. /运算符 :路径拼接更直观,链式语法简洁优雅。
4. 路径分解属性 :parts/parent/name/stem/suffix一次性获取路径所有组成部分,无需手动解析字符串。
5. glob/rglob :模式化文件搜索,比手动递归遍历更高效。
6. 内置读写方法 :read_text/write_text等简化小文件读写,open()上下文管理器支持大文件逐行处理。
7. 跨平台兼容 :自动适应当前操作系统路径格式,无需编写条件判断代码。
8. 不替代os.path所有功能 :某些底层操作(如chmod、chown)仍需使用os模块,但日常路径操作应优先选择pathlib。
# 快速参考 — 常用pathlib代码片段
from pathlib import Path
# 列出当前目录所有Python文件
[ str(f) for f in Path(".").glob("*.py") ]
# 递归删除空目录
[ d.rmdir() for d in Path(".").rglob("*") if d.is_dir() and not list(d.iterdir()) ]
# 安全读取文件(不存在时返回默认值)
def safe_read(path: Path, default: str = "") -> str:
return path.read_text(encoding="utf-8") if path.exists() else default
# 确保目录存在
Path("output/images").mkdir(parents=True, exist_ok=True)
# 文件重命名并保持扩展名
Path("data.csv").with_stem("data_backup") # → data_backup.csv
# 获取精简文件树(可打印)
def tree(dir: Path, prefix: str = ""):
for child in sorted(dir.iterdir()):
yield f"{prefix}├── {child.name}"
if child.is_dir():
yield from tree(child, prefix + "│ ")
print("\n".join(tree(Path("src"))))
总体而言,pathlib不仅仅是os.path的"替代品",它代表了Python文件路径处理从"函数式"到"面向对象"的范式转变。在新项目中应优先使用pathlib,在维护旧代码时也可以逐步迁移,享受面向对象路径操作带来的便利性和代码质量的提升。