【Python】pathlib 模块用于文件路径管理笔记
·
pathlib 是 Python 现代化的文件路径处理模块,它以面向对象的方式操作文件和目录,直观、安全、跨平台。
先看一个小示例,理解 Path 对象的构造、成分解析与常用判断,再看完整速查表和实践技巧。
入门操作和示例
下面这个代码块用于快速理解pathlib的高频基础操作,有助于简表的理解:Path() 构建、成分解析、路径判断、拼接(含 / 与 joinpath 等价说明)、touch() 与 mkdir() 的配合,以及 iterdir() 与 os.walk() 的对比使用法。
from pathlib import Path #Path是pathlib的核心类
import shutil #pathlib结合shutil完成文件移动
import os #用于对比展示
# 1.读取当前目录及文件
Path.cwd() #读取当前目录
list(Path.cwd().iterdir()) # .iterdir()展示当前目录下文件,返回一个惰性generator
# 2. Path() 构建对象(可以传多个组件)
p = Path('project', 'data', 'raw', 'sample.txt')
p1 = Path('project/data/raw/sample.txt')
p2 = Path('project\data\\raw\sample.txt')
print("构建的 Path:", p) # project/data/raw/sample.txt
print(p,"\n",p1,"\n",p2) #三者等价,pathlib会自行处理斜杠方向,但是\在python中是转义字符,且\r是回车符,且因此这里用\\r。综上还是建议培养习惯,使用/运算符
# 3. 成分解析(文件名/后缀/父级等)
print("name:", p.name) # 'sample.txt'
print("stem:", p.stem) # 'sample'
print("suffix:", p.suffix) # '.txt'
print("suffixes:", p.suffixes) # 若有多后缀 e.g. '.tar.gz'
print("parent:", p.parent) # Path('project/data/raw')
# 4. / 操作符 等价于 .joinpath()
a = Path('project') / 'data' / 'raw'
b = Path('project').joinpath('data', 'raw')
assert a == b # True
# 5. Path.touch()创建文件
#注意:Path.touch()不能创建缺失的父目录
f = Path('project/data/newdir/newfile.txt')
try:
f.touch() # 如果 parent 不存在会抛错 FileNotFoundError
except FileNotFoundError:
print("touch 失败,因为父目录不存在")
# 正确做法:先创建父目录,再 touch
f.parent.mkdir(parents=True, exist_ok=True)
f.touch(exist_ok=True)
print("已创建文件:", f)
# 6. 路径判断与解析
print("exists:", f.exists())
print("is_file:", f.is_file())
print("is_dir (parent):", f.parent.is_dir())
print("resolve:", f.resolve()) # 绝对路径并解析符号链接
要点:
/操作符与.joinpath()完全等价,风格上更直观,建议在代码中优先使用/。Path.touch()只会创建文件(或更新时间戳),不会创建不存在的父目录;如果父目录不存在必须先path.parent.mkdir(parents=True, exist_ok=True)。- 在与传统 API(接受字符串路径)交互时,使用
str(path)将其转为字符串。
一、核心思路
- Path 对象即路径:不再需要拼字符串。
- 链式调用:路径解析、拼接、判断、操作可一气呵成。
- 跨平台兼容:自动处理 Windows 与 Linux/macOS 路径差异。
- 与 shutil 协同:完成复制、移动、备份等高级操作。
二、pathlib 高频操作简表
| 类别 | 操作 / 属性 | 关键参数 / 说明 | 常用参数示例 / 值 |
|---|---|---|---|
| 路径创建与拼接 | Path() |
构造路径对象,可拼接多个字符串。 | from pathlib import Path``path = Path('folder', 'subfolder', 'file.txt') |
/ 操作符 |
直观的路径拼接符。 等价于 .joinpath() |
Path('folder') / 'subfolder' / 'file.txt' |
|
.joinpath() |
拼接多个路径组件。 | path.joinpath('subdir', 'file.txt') |
|
| 路径成分解析 | .name |
返回路径的最后部分(文件名+后缀)。 | Path('/a/b.txt').name → 'b.txt' |
.stem |
文件名(无后缀)。 | Path('/a/b.txt').stem → 'b' |
|
.suffix |
文件后缀。 | Path('/a/b.tar.gz').suffix → '.gz' |
|
.suffixes |
所有后缀列表。 | Path('/a/b.tar.gz').suffixes → ['.tar', '.gz'] |
|
.parent |
父级目录路径。 | Path('/a/b.txt').parent → Path('/a') |
|
.parents |
所有上级目录(元组)。 | Path('/a/b/c.txt').parents[0] → Path('/a/b') |
|
.with_name() |
替换文件名部分。 | path.with_name('new_file.txt') |
|
.with_suffix() |
替换文件后缀。 | path.with_suffix('.png') |
|
| 路径解析与判断 | .resolve() |
转为绝对路径并解析符号链接。 | path.resolve() |
.exists() |
判断路径是否存在。 | path.exists() |
|
.is_dir() |
判断是否为目录。 | path.is_dir() |
|
.is_file() |
判断是否为文件。 | path.is_file() |
|
.stat() |
获取文件元信息(大小、修改时间等)。 | path.stat().st_size(文件大小) |
|
| 目录与文件创建 | .mkdir() |
创建目录。 | parents=False(是否创建父级目录)exist_ok=False(目录存在是否报错)示例:Path('data/sub').mkdir(parents=True, exist_ok=True) |
.touch() |
创建空文件或更新访问时间。 注意:不会自动创建父级目录 | mode=0o666, exist_ok=True示例:Path('log.txt').touch(exist_ok=True) |
|
| 重命名与移动 | .rename(target) |
重命名或移动文件(目标存在时报错)。 | Path('a.txt').rename('b.txt') |
.replace(target) |
重命名或移动文件(目标存在则覆盖)。 | Path('a.txt').replace('b.txt') |
|
| 文件读写操作 | .read_text() |
以文本模式读取文件。 | encoding='utf-8'``Path('readme.txt').read_text() |
.write_text() |
以文本模式写入文件。 | encoding='utf-8'``Path('out.txt').write_text('Hello!') |
|
.read_bytes() |
以二进制模式读取文件。 | Path('data.bin').read_bytes() |
|
.write_bytes() |
以二进制模式写入文件。 | Path('data.bin').write_bytes(b'data') |
|
| 文件与目录删除 | .unlink() |
删除文件。 | missing_ok=False``Path('old.txt').unlink(missing_ok=True) |
.rmdir() |
删除空目录。 | Path('tmp').rmdir() |
|
| 目录遍历与匹配 | .iterdir() |
遍历目录下所有条目。 返回 generator(惰性) | for p in Path('folder').iterdir(): print(p) |
.glob(pattern) |
匹配模式(非递归)。 | Path('.').glob('*.py') |
|
.rglob(pattern) |
递归匹配模式。 | Path('.').rglob('**/*.txt') |
|
| 文件操作(结合 shutil) | shutil.copy(src, dst) |
复制文件内容,不含元数据。 | import shutil``shutil.copy(Path('source.txt'), Path('copy.txt')) |
shutil.copy2(src, dst) |
复制文件并保留元数据。 | shutil.copy2(Path('source.txt'), Path('backup/source.txt')) |
|
shutil.copytree(src, dst) |
递归复制整个目录树。 | shutil.copytree(Path('src_dir'), Path('backup_dir')) |
|
shutil.rmtree() |
删除文件夹。【慎用】 | shutil.rmtree("./subfolder") |
三、实用示例与技巧
1️⃣ 创建目录与文件
from pathlib import Path
# 创建目录及父目录
data_dir = Path('data/raw')
data_dir.mkdir(parents=True, exist_ok=True)
# 创建文件(注意:touch 不会创建父目录,因此要先 mkdir)
file_path = data_dir / 'sample.txt'
file_path.touch(exist_ok=True)
2️⃣ 文件复制(与 shutil 搭配)
from pathlib import Path
import shutil
src_path = Path('data/raw/sample.txt')
dst_path = Path('backup/sample_backup.txt')
# 确保目标目录存在
dst_path.parent.mkdir(parents=True, exist_ok=True)
# 复制文件(保留元数据)
shutil.copy2(src_path, dst_path)
3️⃣ 安全重命名与覆盖
from pathlib import Path
src = Path('backup/sample_backup.txt')
dst = Path('backup/sample_final.txt')
# rename:若目标已存在,会报错
# replace:若目标已存在,会覆盖
src.replace(dst)
4️⃣ 遍历目录与模式匹配
from pathlib import Path
for txt_file in Path('data').rglob('*.txt'):
print(txt_file.name)
5️⃣ 文件存在性与删除
file = Path('temp.txt')
if file.exists():
file.unlink() # 删除文件
6️⃣rglob递归遍历
| 场景 | 一行式代码 |
|---|---|
| 递归拿到所有文件(含子目录) | file_list = [p for p in Path(src).rglob('*') if p.is_file()] |
| 仅匹配某种后缀 | py_files = list(Path(src).rglob('*.py')) |
| 递归只取目录 | dir_list = [p for p in Path(src).rglob('*') if p.is_dir()] |
| 收集所有文件名(不含路径) | names = [p.name for p in Path(src).rglob('*') if p.is_file()] |
| 按后缀分组 | suffix2files = defaultdict(list); [suffix2files[p.suffix].append(p) for p in Path(src).rglob('*') if p.is_file()] |
| 最深层级文件(深度最大) | depth2files = defaultdict(list); [depth2files[len(p.relative_to(src).parts)].append(p) for p in Path(src).rglob('*') if p.is_file()]; deepest = depth2files[max(depth2files)] |
> rglob('*') 是 pathlib 的递归神器,返回生成器,惰性省内存;搭配列表推导即可一次性拿到结果。
6️⃣批量复制文件(pathlib + shutil)
from pathlib import Path
import shutil
# 待移动文件列表(遍历Path对象获得.txt后缀的文件)
file_tomove = list(Path("F:/file_source/").rglob("*.txt")) #注意要展开为list,否则是generator,循环只能使用一次
# 或者直接for循环遍历生成器: Path("F:/file_source/").rglob("*.txt")
destination = Path('H:/target_fold')
destination.mkdir(parents=True, exist_ok=True) # 建目录
#1.易读,耗内存
for src in file_tomove:
shutil.copy(src, destination / src.name) # 同名移动
#2.节约内存,快速,不易读
for src in Path("F:/file_source/").rglob("*.txt"):
shutil.copy(src, destination / src.name) # 同名移动
7️⃣ 更换文件名(with_name)
src = Path('data/raw/sample.txt')
dst = src.with_name('sample_backup.txt') # 仅改文件名,保留原父目录
src.replace(dst) #执行修改
8️⃣ 批量更换后缀(with_suffix)
from pathlib import Path
p=Path.cwd()
Path(p/"fold_Practise").mkdir(exist_ok=True)
for n in range(10):
(p/"fold_Practise"/f"{n}file.md").touch(exist_ok=True) #创建练习用文件夹及1-10file.md文件
src=list((p/"fold_Practise").iterdir())#提取fold_practise下所有文件
for f in src:
new_name=f.with_suffix(".png") # 仅改后缀,其余不变
f.replace(new_name) #执行修改
四、rename() 与 replace() 的区别
| 特性 | Path.rename(target) |
Path.replace(target) |
|---|---|---|
| 目标已存在时 | 抛出 FileExistsError |
无条件覆盖 |
| 主要用途 | 安全移动 / 重命名 | 强制移动 / 覆盖式重命名 |
| 目标路径不存在时 | 抛出 FileNotFoundError |
同样抛出 FileNotFoundError |
五、常见陷阱与建议
-
路径对象不是字符串:与旧函数交互时使用
str(path)将其转为字符串。 -
性能考虑:大量文件遍历时,
os.walk()可能略快,但 pathlib 更安全可读。 -
异常处理示例:
try: shutil.copy2(Path('a.txt'), Path('b.txt')) except FileNotFoundError: print("源文件不存在。") except PermissionError: print("权限不足。") -
一行式链式调用示例:
content = Path('data.txt').resolve().parent.joinpath('config.ini').read_text(encoding='utf-8') -
关于 iterdir():
# iterdir() 与 os.walk() 对比(两者都可遍历目录) print("Path.iterdir()(生成器,返回当前目录条目,非递归):") for entry in Path('project').iterdir(): print("-", entry) print("os.walk()(递归、三层元组:dirpath, dirnames, filenames):") for dirpath, dirnames, filenames in os.walk('project'): print(dirpath, dirnames, filenames) # 小结: # - Path.iterdir() 返回生成器(generator),只列出当前目录下的条目(文件/子目录) # - os.walk() 返回**递归**遍历的三元组:更适合复杂的递归遍历需求 # - Path.rglob('*.txt') 可以做递归匹配,通常比 os.walk 更直观、更像 Path 的风格Path.iterdir()返回 生成器(generator),列出当前目录下的条目(文件和子目录),非递归。os.walk()返回递归遍历所需的三元组(dirpath, dirnames, filenames);若只需列出当前目录项,用iterdir()更直观;若需递归或控制子目录遍历,使用os.walk()或rglob()更合适。
六、总结
pathlib让路径管理更直观:对象化 + 链式操作 + 跨平台。- 配合
shutil可完成复制、备份、迁移任务。 - 熟练掌握
.mkdir()与.touch()是文件系统自动化脚本的核心。
延伸阅读
- 官方文档:https://docs.python.org/3/library/pathlib.html
- 相关模块:
os、shutil、tempfile
更多推荐
所有评论(0)