【第7章 I/O编程与异常】Python 路径与目录操作全解析:核心库、用法与实例
Python 文件与目录操作全解析:核心库、用法与实例
Python 提供了多个用于文件/目录操作的标准库,涵盖路径处理、文件读写、目录遍历、权限管理等核心场景。本文将系统梳理 6 个核心库(os、os.path、pathlib、shutil、glob、fnmatch),从「功能定位、核心 API、实例代码、适用场景」四个维度展开,所有代码均可直接运行,兼顾基础用法与实战场景。
一、核心库概览:功能定位与选型指南
| 库名 | 核心功能 | 设计风格 | 适用场景 | Python 版本要求 |
|---|---|---|---|---|
os |
底层系统调用(目录创建/删除、进程、权限) | 函数式 API | 基础目录操作、系统交互 | 全版本支持 |
os.path |
路径字符串处理(拼接、判断、拆分) | 函数式 API | 路径格式化、合法性校验(兼容 Python 2/3) | 全版本支持 |
pathlib |
面向对象的路径操作(推荐!) | 类实例化 API | 现代 Python 路径处理(简洁、易读) | 3.4+ |
shutil |
高级文件/目录操作(复制、移动、归档) | 函数式 API | 文件批量复制、目录合并、压缩解压 | 全版本支持 |
glob |
路径模式匹配(通配符查找文件) | 函数式 API | 按文件名/后缀批量查找文件 | 全版本支持 |
fnmatch |
文件名模式匹配(单独字符串匹配) | 函数式 API | 自定义文件名过滤规则(不依赖路径) | 全版本支持 |
选型原则:
- Python 3.4+ 优先用
pathlib:面向对象设计,代码更简洁,支持链式调用; - 兼容旧版本用
os + os.path:全版本支持,生态成熟; - 高级操作(复制/移动/压缩)用
shutil; - 批量查找文件用
glob; - 仅文件名匹配用
fnmatch。
二、分库详解与实例代码
1. os 库:底层系统级文件/目录操作
os 库直接调用操作系统接口,提供最基础的文件/目录操作,如创建目录、删除目录、列出目录内容等。
核心 API 与实例
| 功能 | 核心函数 | 实例代码 |
|---|---|---|
| 列出目录内容 | os.listdir(path) |
列出指定目录下的所有文件/子目录(返回字符串列表) |
| 创建目录 | os.mkdir(path)(单级)、os.makedirs(path)(多级) |
创建单级/多级目录,makedirs 支持递归创建(如 a/b/c) |
| 删除目录 | os.rmdir(path)(单级)、os.removedirs(path)(多级) |
删除空目录,removedirs 递归删除空父目录 |
| 删除文件 | os.remove(path) / os.unlink(path) |
两者功能完全一致,删除指定文件 |
| 重命名文件/目录 | os.rename(src, dst) |
重命名文件或目录,跨分区移动时可能失败(推荐用 shutil.move) |
| 获取当前工作目录 | os.getcwd() |
返回当前 Python 脚本运行的工作目录 |
| 切换工作目录 | os.chdir(path) |
切换到指定目录(类似 cd 命令) |
| 判断路径类型 | os.path.isfile(path) / os.path.isdir(path) |
后续 os.path 库详细讲解 |
实战代码:
import os
# 1. 查看当前工作目录
print("当前工作目录:", os.getcwd()) # 输出示例:/Users/username/project
# 2. 列出目录内容(以当前目录为例)
print("\n当前目录内容:", os.listdir(".")) # 返回 [文件名1, 目录名1, ...]
# 3. 创建目录(单级 + 多级)
os.mkdir("test_single_dir") # 创建单级目录(已存在会报错)
os.makedirs("test_multi_dir/a/b/c", exist_ok=True) # 递归创建多级目录,exist_ok=True 避免已存在报错
# 4. 重命名目录
os.rename("test_single_dir", "renamed_dir") # 将 test_single_dir 重命名为 renamed_dir
# 5. 切换工作目录
os.chdir("renamed_dir")
print("\n切换后工作目录:", os.getcwd()) # 输出:/Users/username/project/renamed_dir
os.chdir("..") # 回到上级目录
# 6. 删除目录(空目录)
os.rmdir("renamed_dir") # 删除单级空目录
os.removedirs("test_multi_dir/a/b/c") # 递归删除空目录(从最内层开始,直到父目录非空)
# 7. 创建并删除文件
with open("test_file.txt", "w") as f:
f.write("测试文件")
os.remove("test_file.txt") # 删除文件(也可用 os.unlink("test_file.txt"))
注意事项:
os.mkdir只能创建单级目录,若父目录不存在会报错;os.rmdir只能删除空目录,若目录非空需先删除内部文件/子目录(可结合shutil.rmtree);os.rename跨文件系统(如 C 盘→D 盘)移动文件时可能失败,推荐用shutil.move。
2. os.path 库:路径字符串处理
os.path 是 os 库的子模块,专门用于路径字符串的拼接、拆分、判断等操作,兼容 Windows(\)和 Linux/Mac(/)路径格式。
核心 API 与实例
| 功能 | 核心函数 | 实例代码 |
|---|---|---|
| 路径拼接 | os.path.join(path1, path2, ...) |
自动根据系统拼接路径(避免手动写 / 或 \) |
| 拆分路径(目录+文件名) | os.path.split(path) |
返回元组 (目录路径, 文件名) |
| 拆分扩展名 | os.path.splitext(path) |
返回元组 (路径(不含扩展名), 扩展名) |
| 获取文件名 | os.path.basename(path) |
返回路径中的文件名(含扩展名) |
| 获取目录路径 | os.path.dirname(path) |
返回路径中的目录部分 |
| 判断路径存在 | os.path.exists(path) |
判断文件/目录是否存在 |
| 判断是否为文件 | os.path.isfile(path) |
判断路径是否为文件 |
| 判断是否为目录 | os.path.isdir(path) |
判断路径是否为目录 |
| 获取绝对路径 | os.path.abspath(path) |
将相对路径转为绝对路径 |
| 计算相对路径 | os.path.relpath(path, start) |
计算从 start 目录到 path 的相对路径 |
实战代码:
import os.path
# 1. 路径拼接(跨平台兼容)
path1 = os.path.join("root", "dir", "file.txt") # Linux/Mac 输出:root/dir/file.txt;Windows 输出:root\dir\file.txt
print("拼接路径:", path1)
# 2. 拆分路径
full_path = "/Users/username/project/file.txt"
dir_path, filename = os.path.split(full_path)
print("\n拆分路径 - 目录:", dir_path) # 输出:/Users/username/project
print("拆分路径 - 文件名:", filename) # 输出:file.txt
# 3. 拆分扩展名
name_without_ext, ext = os.path.splitext(filename)
print("\n拆分扩展名 - 无扩展名:", name_without_ext) # 输出:file
print("拆分扩展名 - 扩展名:", ext) # 输出:.txt
# 4. 获取文件名/目录路径
print("\n文件名(含扩展名):", os.path.basename(full_path)) # 输出:file.txt
print("目录路径:", os.path.dirname(full_path)) # 输出:/Users/username/project
# 5. 路径判断
print("\n路径是否存在:", os.path.exists(full_path)) # 输出:False(示例路径,实际需替换为真实路径)
print("是否为文件:", os.path.isfile(full_path)) # 输出:False
print("是否为目录:", os.path.isdir(os.path.dirname(full_path))) # 输出:True(若目录存在)
# 6. 绝对路径与相对路径
relative_path = "../project/file.txt"
print("\n绝对路径:", os.path.abspath(relative_path)) # 输出:/Users/username/project/file.txt(根据当前工作目录转换)
print("相对路径:", os.path.relpath(full_path, "/Users/username")) # 输出:project/file.txt
核心优势:
- 跨平台兼容:自动适配不同系统的路径分隔符;
- 安全可靠:避免手动拼接路径导致的语法错误(如多写
/或漏写)。
3. pathlib 库:面向对象的路径操作(推荐)
pathlib 是 Python 3.4+ 引入的现代路径处理库,采用面向对象设计,将路径视为「对象」而非字符串,支持链式调用,代码更简洁易读。
核心概念:
Path类:pathlib的核心类,实例化后代表一个路径(文件或目录);- 支持链式调用:如
Path("root").joinpath("dir").joinpath("file.txt")可简化为Path("root") / "dir" / "file.txt"; - 方法封装:将
os和os.path的功能封装为实例方法(如exists()、is_file()、mkdir())。
核心 API 与实例
| 功能 | pathlib 方法 |
对应 os/os.path 函数 |
|---|---|---|
| 路径拼接 | Path("/a") / "b" / "c.txt" |
os.path.join("/a", "b", "c.txt") |
| 创建目录 | path.mkdir(parents=True, exist_ok=True) |
os.makedirs(path, exist_ok=True) |
| 列出目录内容 | list(path.iterdir()) |
os.listdir(path) |
| 路径判断 | path.exists() / path.is_file() / path.is_dir() |
os.path.exists() / os.path.isfile() / os.path.isdir() |
| 拆分路径 | path.parent(目录)、path.name(文件名)、path.stem(无扩展名)、path.suffix(扩展名) |
os.path.dirname() / os.path.basename() / os.path.splitext() |
| 绝对路径 | path.absolute() |
os.path.abspath(path) |
| 重命名/移动 | path.rename(new_path) |
os.rename(path, new_path) |
| 删除文件/目录 | path.unlink()(文件)、path.rmdir()(空目录) |
os.remove(path) / os.rmdir(path) |
实战代码:
from pathlib import Path
# 1. 实例化 Path 对象(支持相对路径和绝对路径)
current_dir = Path(".") # 当前目录
full_path = Path("/Users/username/project/file.txt") # 绝对路径
# 2. 路径拼接(链式调用,推荐用 / 运算符)
new_path = Path("root") / "dir" / "file.txt"
print("拼接路径:", new_path) # 输出:root/dir/file.txt(根据系统自动适配分隔符)
# 3. 路径属性(无需函数调用,直接访问属性)
print("\n目录路径(parent):", full_path.parent) # 输出:/Users/username/project
print("文件名(name):", full_path.name) # 输出:file.txt
print("无扩展名(stem):", full_path.stem) # 输出:file
print("扩展名(suffix):", full_path.suffix) # 输出:.txt
print("绝对路径:", new_path.absolute()) # 输出:/Users/username/project/root/dir/file.txt
# 4. 路径判断
print("\n路径是否存在:", full_path.exists()) # 输出:False
print("是否为文件:", full_path.is_file()) # 输出:False
print("是否为目录:", current_dir.is_dir()) # 输出:True
# 5. 创建目录(支持递归创建)
dir_path = Path("test_pathlib_dir/a/b/c")
dir_path.mkdir(parents=True, exist_ok=True) # parents=True 递归创建,exist_ok=True 避免已存在报错
print("\n目录是否创建成功:", dir_path.exists()) # 输出:True
# 6. 列出目录内容(返回 Path 对象列表,可直接操作)
print("\n当前目录内容:")
for item in current_dir.iterdir():
print(f" {'目录' if item.is_dir() else '文件'}: {item.name}")
# 7. 创建并删除文件
file_path = Path("test_pathlib.txt")
file_path.write_text("Hello Pathlib!") # 写入文件(替代 open 函数)
print("\n文件内容:", file_path.read_text()) # 读取文件,输出:Hello Pathlib!
file_path.unlink() # 删除文件
# 8. 重命名目录
new_dir_path = Path("renamed_pathlib_dir")
dir_path.parent.rename(new_dir_path) # 将 test_pathlib_dir/a 重命名为 renamed_pathlib_dir
print("\n目录重命名后是否存在:", new_dir_path.exists()) # 输出:True
# 9. 删除目录(空目录)
new_dir_path.rmdir() # 删除单级空目录
dir_path.parent.parent.rmdir() # 删除上级空目录
核心优势:
- 代码更简洁:用属性替代函数(如
path.parent替代os.path.dirname(path)); - 链式调用:路径拼接用
/运算符,逻辑更清晰; - 类型安全:返回的是
Path对象,而非字符串,可直接调用方法操作(如write_text()、read_text()); - 功能更全面:整合了
os和os.path的所有核心功能,且支持更多高级操作(如 glob 匹配、文件迭代)。
4. shutil 库:高级文件/目录操作
shutil 库基于 os 库封装,提供更高级的文件/目录操作,如批量复制、移动、删除非空目录、压缩解压等,是实战中常用的工具库。
- shutil 是 "shell utilities" 的缩写,意为 “shell 工具”。
- 这个库的命名源于其功能定位:它提供了一系列与操作系统 shell(命令行外壳)相关的高级文件操作工具,比如复制、移动、删除文件 / 目录、压缩解压等,相当于 Python 对 shell 中常见文件管理命令(如 cp、mv、rm、tar 等)的封装。
- 简单说,shutil 的设计目标是简化那些在 shell 中常用的文件操作,让开发者无需直接调用系统命令(如 os.system("cp ...")),就能通过 Python 代码安全、跨平台地完成复杂的文件管理任务。
核心 API 与实例
| 功能 | 核心函数 | 实例代码 |
|---|---|---|
| 复制文件 | shutil.copy(src, dst) |
复制文件内容和权限,dst 可为目录或新文件名 |
| 复制文件+元数据 | shutil.copy2(src, dst) |
复制文件内容和所有元数据(创建时间、修改时间等) |
| 复制目录(递归) | shutil.copytree(src, dst) |
递归复制整个目录树(dst 必须不存在) |
| 移动文件/目录 | shutil.move(src, dst) |
移动文件/目录,支持跨分区移动,可同时重命名 |
| 删除非空目录 | shutil.rmtree(path) |
递归删除目录及内部所有文件/子目录(危险操作,谨慎使用) |
| 压缩文件 | shutil.make_archive(base_name, format, root_dir) |
创建归档文件(zip、tar、gztar 等格式) |
| 解压文件 | shutil.unpack_archive(filename, extract_dir) |
解压归档文件到指定目录 |
| 查看磁盘空间 | shutil.disk_usage(path) |
返回指定路径所在磁盘的总空间、已用空间、可用空间(单位:字节) |
实战代码:
import shutil
from pathlib import Path
# 准备工作:创建测试文件和目录
src_dir = Path("source_dir")
src_dir.mkdir(exist_ok=True)
# 在 source_dir 中创建文件和子目录
with open(src_dir / "file1.txt", "w") as f:
f.write("文件1内容")
with open(src_dir / "file2.txt", "w") as f:
f.write("文件2内容")
sub_dir = src_dir / "sub_dir"
sub_dir.mkdir(exist_ok=True)
with open(sub_dir / "file3.txt", "w") as f:
f.write("子目录文件3内容")
# 1. 复制文件(copy / copy2)
dst_file1 = Path("copy_file1.txt")
shutil.copy(src_dir / "file1.txt", dst_file1) # 复制文件内容和权限
print("copy 复制文件是否存在:", dst_file1.exists()) # True
dst_file2 = Path("copy_file2.txt")
shutil.copy2(src_dir / "file1.txt", dst_file2) # 复制文件内容+元数据(创建时间等)
print("copy2 复制文件是否存在:", dst_file2.exists()) # True
# 2. 复制目录(copytree:递归复制整个目录树)
dst_dir = Path("dest_dir")
shutil.copytree(src_dir, dst_dir) # dst_dir 必须不存在,否则报错
print("\n复制目录是否存在:", dst_dir.exists()) # True
print("复制目录下的文件:", list(dst_dir.glob("*"))) # [dest_dir/file1.txt, dest_dir/file2.txt, dest_dir/sub_dir]
# 3. 移动文件/目录(move:支持跨分区、重命名)
# 移动文件
move_file = Path("moved_file.txt")
shutil.move(dst_file1, move_file) # 将 copy_file1.txt 移动并重命名为 moved_file.txt
print("\n移动后的文件是否存在:", move_file.exists()) # True
print("原文件是否存在:", dst_file1.exists()) # False
# 移动目录
move_dir = Path("moved_dir")
shutil.move(dst_dir, move_dir) # 将 dest_dir 移动并重命名为 moved_dir
print("移动后的目录是否存在:", move_dir.exists()) # True
print("原目录是否存在:", dst_dir.exists()) # False
# 4. 删除非空目录(rmtree:递归删除,危险操作!)
shutil.rmtree(move_dir) # 删除 moved_dir 及内部所有文件/子目录
print("\n删除的目录是否存在:", move_dir.exists()) # False
# 5. 压缩文件(make_archive)
# 创建 zip 格式压缩包:base_name=压缩包名(不含扩展名),format=压缩格式,root_dir=要压缩的目录
archive_name = "compressed_archive"
shutil.make_archive(archive_name, "zip", root_dir=src_dir) # 生成 compressed_archive.zip
print("\n压缩包是否存在:", Path(f"{archive_name}.zip").exists()) # True
# 6. 解压文件(unpack_archive)
extract_dir = Path("extracted_dir")
shutil.unpack_archive(f"{archive_name}.zip", extract_dir) # 解压到 extracted_dir
print("解压目录是否存在:", extract_dir.exists()) # True
print("解压目录内容:", list(extract_dir.glob("**/*"))) # 递归列出所有解压后的文件
# 7. 查看磁盘空间
disk_usage = shutil.disk_usage("/") # Unix 查看根目录,Windows 用 "C:"
print("\n磁盘总空间:", disk_usage.total // 1024 // 1024 // 1024, "GB") # 转换为 GB
print("磁盘已用空间:", disk_usage.used // 1024 // 1024 // 1024, "GB")
print("磁盘可用空间:", disk_usage.free // 1024 // 1024 // 1024, "GB")
# 清理测试文件
move_file.unlink()
dst_file2.unlink()
shutil.rmtree(extract_dir)
shutil.rmtree(src_dir)
Path(f"{archive_name}.zip").unlink()
关键注意事项:
shutil.copytree的目标目录(dst)必须不存在,否则报错;若需覆盖,需手动删除目标目录或使用第三方库(如distutils.dir_util.copy_tree);shutil.rmtree是危险操作,会递归删除目录及所有内容,无恢复机制,建议操作前添加确认逻辑;shutil.move跨分区移动时,会先复制文件再删除原文件(避免移动失败导致数据丢失),本地移动则直接重命名(效率更高)。
5. glob 库:路径模式匹配(批量查找文件)
glob 库用于按通配符模式批量查找文件/目录,支持 *(匹配任意字符)、?(匹配单个字符)、[](匹配指定字符集)等通配符,比 os.listdir 更灵活。
核心通配符说明
| 通配符 | 含义 | 示例 | 匹配结果 |
|---|---|---|---|
* |
匹配任意数量的字符(含0个) | *.txt |
所有后缀为 .txt 的文件 |
? |
匹配单个字符 | file?.txt |
file1.txt、fileA.txt(不匹配 file10.txt) |
[] |
匹配括号内的任意一个字符 | file[1-3].txt |
file1.txt、file2.txt、file3.txt |
** |
递归匹配所有子目录(需配合 recursive=True) |
**/*.txt |
所有子目录中后缀为 .txt 的文件 |
核心 API 与实例
| 功能 | 核心函数 | 实例代码 |
|---|---|---|
| 查找匹配路径 | glob.glob(pathname, recursive=False) |
返回匹配的路径字符串列表,recursive=True 支持递归查找 |
| 查找匹配路径(生成器) | glob.iglob(pathname, recursive=False) |
返回生成器(逐个输出路径,节省内存) |
| 大小写不敏感匹配 | glob.glob(pathname, recursive=False, case_sensitive=False) |
Python 3.10+ 支持,忽略大小写 |
实战代码:
import glob
from pathlib import Path
# 准备工作:创建测试目录和文件
test_glob_dir = Path("test_glob")
test_glob_dir.mkdir(exist_ok=True)
# 创建不同类型的文件
for i in range(3):
(test_glob_dir / f"file{i}.txt").write_text(f"文件{i}")
(test_glob_dir / f"doc{i}.pdf").write_text(f"文档{i}")
# 创建子目录并添加文件
sub_glob_dir = test_glob_dir / "sub_dir"
sub_glob_dir.mkdir(exist_ok=True)
(sub_glob_dir / "file4.txt").write_text("子目录文件4")
(sub_glob_dir / "image.png").write_text("图片文件")
# 1. 匹配当前目录下的所有 .txt 文件(非递归)
txt_files = glob.glob("test_glob/*.txt")
print("非递归匹配 .txt 文件:", txt_files)
# 输出示例:['test_glob/file0.txt', 'test_glob/file1.txt', 'test_glob/file2.txt']
# 2. 匹配所有 .pdf 文件
pdf_files = glob.glob("test_glob/*.pdf")
print("\n匹配 .pdf 文件:", pdf_files)
# 输出示例:['test_glob/doc0.pdf', 'test_glob/doc1.pdf', 'test_glob/doc2.pdf']
# 3. 匹配 file1.txt ~ file3.txt(用 [] 通配符)
file_range_files = glob.glob("test_glob/file[1-3].txt")
print("\n匹配 file1-file3.txt:", file_range_files)
# 输出示例:['test_glob/file1.txt', 'test_glob/file2.txt'](无 file3.txt,不匹配)
# 4. 递归匹配所有子目录中的 .txt 文件(Python 3.5+ 支持 **)
all_txt_files = glob.glob("test_glob/**/*.txt", recursive=True)
print("\n递归匹配所有 .txt 文件:", all_txt_files)
# 输出示例:['test_glob/file0.txt', 'test_glob/file1.txt', 'test_glob/file2.txt', 'test_glob/sub_dir/file4.txt']
# 5. 用 iglob 生成器(适合大量文件,节省内存)
print("\n用 iglob 生成器输出 .png 文件:")
for png_file in glob.iglob("test_glob/**/*.png", recursive=True):
print(f" {png_file}") # 输出:test_glob/sub_dir/image.png
# 6. 大小写不敏感匹配(Python 3.10+)
# case_insensitive_files = glob.glob("test_glob/**/*.TXT", recursive=True, case_sensitive=False)
# print("\n大小写不敏感匹配 .TXT:", case_insensitive_files)
# 清理测试目录
import shutil
shutil.rmtree(test_glob_dir)
核心优势:
- 语法简洁:用通配符替代手动过滤,代码更简洁;
- 支持递归:
**+recursive=True可快速查找所有子目录中的文件; - 与
pathlib兼容:可将匹配结果转换为Path对象操作:txt_paths = [Path(path) for path in glob.glob("test_glob/*.txt")] for path in txt_paths: print(path.read_text()) # 直接读取文件内容
6. fnmatch 库:文件名模式匹配(单独字符串匹配)
fnmatch 库专注于单个文件名/字符串的模式匹配,语法与 glob 一致,但不依赖路径,仅对字符串进行匹配判断,适合自定义文件过滤规则。
核心 API 与实例
| 功能 | 核心函数 | 实例代码 |
|---|---|---|
| 判断字符串是否匹配模式 | fnmatch.fnmatch(name, pat) |
返回布尔值,name 为字符串,pat 为匹配模式 |
| 大小写不敏感匹配 | fnmatch.fnmatchcase(name, pat) |
严格区分大小写(默认),fnmatch 会根据系统自动处理大小写(Windows 不敏感,Unix 敏感) |
| 过滤列表 | fnmatch.filter(names, pat) |
从列表 names 中过滤出匹配模式 pat 的元素 |
实战代码:
import fnmatch
import os
# 1. 单个文件名匹配
filename1 = "file.txt"
filename2 = "image.png"
filename3 = "file123.txt"
# 匹配 .txt 文件
print(f"fnmatch('{filename1}', '*.txt'): {fnmatch.fnmatch(filename1, '*.txt')}") # True
print(f"fnmatch('{filename2}', '*.txt'): {fnmatch.fnmatch(filename2, '*.txt')}") # False
# 匹配 file 开头 + 数字 + .txt
print(f"\nfnmatch('{filename3}', 'file[0-9]*.txt'): {fnmatch.fnmatch(filename3, 'file[0-9]*.txt')}") # True
# 2. 大小写敏感 vs 不敏感
filename4 = "File.TXT"
print(f"\nfnmatch('{filename4}', '*.txt'): {fnmatch.fnmatch(filename4, '*.txt')}") # Windows 为 True,Unix 为 False
print(f"fnmatchcase('{filename4}', '*.txt'): {fnmatch.fnmatchcase(filename4, '*.txt')}") # 严格区分,返回 False
# 3. 过滤文件列表(模拟目录文件列表)
file_list = [
"file1.txt", "doc.pdf", "image.png",
"file2.txt", "file3.csv", "File.TXT"
]
# 过滤所有 .txt 文件
txt_files = fnmatch.filter(file_list, "*.txt")
print("\n过滤 .txt 文件:", txt_files) # 输出:['file1.txt', 'file2.txt'](Unix 系统)或 ['file1.txt', 'file2.txt', 'File.TXT'](Windows 系统)
# 过滤 file 开头的文件
file_prefix_files = fnmatch.filter(file_list, "file*")
print("过滤 file 开头的文件:", file_prefix_files) # 输出:['file1.txt', 'file2.txt', 'file3.csv']
# 4. 结合 os.listdir 过滤目录文件
# 模拟目录遍历(实际使用时替换为真实目录)
def filter_dir_files(dir_path, pattern):
for filename in os.listdir(dir_path):
if fnmatch.fnmatch(filename, pattern):
yield os.path.join(dir_path, filename)
# 示例:过滤当前目录下的 .py 文件
print("\n当前目录下的 .py 文件:")
for py_file in filter_dir_files(".", "*.py"):
print(f" {py_file}")
适用场景:
- 仅需对文件名(而非路径)进行匹配;
- 自定义文件过滤逻辑(如在
os.listdir遍历后过滤); - 需严格控制大小写匹配规则。
三、实战场景综合示例
场景1:批量重命名指定目录下的文件
需求:将 data 目录下所有 .txt 文件重命名为 prefix_001.txt、prefix_002.txt 格式。
from pathlib import Path
# 1. 定义目录和前缀
dir_path = Path("data")
dir_path.mkdir(exist_ok=True)
prefix = "prefix"
# 2. 创建测试文件
for i in range(5):
(dir_path / f"file{i+1}.txt").write_text(f"测试文件{i+1}")
# 3. 批量重命名
txt_files = sorted(dir_path.glob("*.txt")) # 按文件名排序
for idx, file in enumerate(txt_files, 1):
# 生成新文件名:prefix_001.txt(3位数字,不足补0)
new_filename = f"{prefix}_{idx:03d}.txt"
new_file_path = dir_path / new_filename
file.rename(new_file_path) # 重命名
print(f"重命名:{file.name} → {new_filename}")
# 输出示例:
# 重命名:file1.txt → prefix_001.txt
# 重命名:file2.txt → prefix_002.txt
# 重命名:file3.txt → prefix_003.txt
# 重命名:file4.txt → prefix_004.txt
# 重命名:file5.txt → prefix_005.txt
# 清理测试目录
import shutil
shutil.rmtree(dir_path)
场景2:递归查找并复制指定类型文件
需求:查找 source 目录及其子目录下所有 .jpg 和 .png 文件,复制到 dest/images 目录。
import shutil
from pathlib import Path
# 1. 定义源目录和目标目录
src_dir = Path("source")
dst_dir = Path("dest/images")
dst_dir.mkdir(parents=True, exist_ok=True)
# 2. 创建测试文件和目录
src_dir.mkdir(exist_ok=True)
(src_dir / "pic1.jpg").touch()
(src_dir / "pic2.png").touch()
sub_src_dir = src_dir / "sub"
sub_src_dir.mkdir(exist_ok=True)
(sub_src_dir / "pic3.jpg").touch()
(sub_src_dir / "doc.txt").touch() # 非图片文件,不复制
# 3. 递归查找图片文件(.jpg 和 .png)
image_patterns = ["*.jpg", "*.png"]
for pattern in image_patterns:
for image_file in src_dir.glob(f"**/{pattern}"): # 递归查找
# 复制文件到目标目录,保持原文件名
dst_file = dst_dir / image_file.name
shutil.copy2(image_file, dst_file)
print(f"复制:{image_file} → {dst_file}")
# 输出示例:
# 复制:source/pic1.jpg → dest/images/pic1.jpg
# 复制:source/sub/pic3.jpg → dest/images/pic3.jpg
# 复制:source/pic2.png → dest/images/pic2.png
# 验证复制结果
print("\n目标目录文件列表:")
for file in dst_dir.glob("*"):
print(f" {file.name}") # 输出:pic1.jpg、pic2.png、pic3.jpg
# 清理测试目录
shutil.rmtree(src_dir)
shutil.rmtree(dst_dir.parent)
场景3:按文件大小筛选并压缩
需求:查找 logs 目录中大小超过 1MB 的日志文件(.log),压缩为 large_logs.zip 并删除原文件。
import shutil
import zipfile
from pathlib import Path
# 1. 定义目录和阈值(1MB = 1024*1024 字节)
log_dir = Path("logs")
log_dir.mkdir(exist_ok=True)
SIZE_THRESHOLD = 1024 * 1024 # 1MB
# 2. 创建测试文件(模拟大日志文件)
large_log1 = log_dir / "app1.log"
with open(large_log1, "wb") as f:
f.seek(SIZE_THRESHOLD + 100) # 大小略大于1MB
f.write(b"\x00")
large_log2 = log_dir / "app2.log"
with open(large_log2, "wb") as f:
f.seek(SIZE_THRESHOLD + 200)
f.write(b"\x00")
small_log = log_dir / "debug.log"
with open(small_log, "wb") as f:
f.seek(1024) # 1KB 小文件
f.write(b"\x00")
# 3. 筛选大日志文件
large_logs = []
for log_file in log_dir.glob("*.log"):
if log_file.stat().st_size > SIZE_THRESHOLD: # 获取文件大小
large_logs.append(log_file)
print(f"找到大日志文件:{log_file.name}({log_file.stat().st_size//1024}KB)")
# 4. 压缩大日志文件
zip_path = Path("large_logs.zip")
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zipf:
for log_file in large_logs:
zipf.write(log_file, arcname=log_file.name) # arcname 保留文件名,去除路径
print(f"压缩:{log_file.name} → {zip_path.name}")
# 5. 删除原大日志文件
for log_file in large_logs:
log_file.unlink()
print(f"删除原文件:{log_file.name}")
# 输出示例:
# 找到大日志文件:app1.log(1025KB)
# 找到大日志文件:app2.log(1025KB)
# 压缩:app1.log → large_logs.zip
# 压缩:app2.log → large_logs.zip
# 删除原文件:app1.log
# 删除原文件:app2.log
# 清理测试目录
shutil.rmtree(log_dir)
zip_path.unlink()
四、库功能对比与最佳实践总结
1. 功能对比表
| 操作场景 | 推荐库/方法 | 替代方案 |
|---|---|---|
| 路径拼接/拆分 | pathlib.Path(/ 运算符) |
os.path.join / os.path.split |
| 创建/删除目录 | pathlib.Path.mkdir() / rmdir() |
os.mkdir / os.rmdir |
| 递归创建/删除目录 | pathlib.Path.mkdir(parents=True) / shutil.rmtree() |
os.makedirs / os.removedirs(仅空目录) |
| 复制文件/目录 | shutil.copy2() / shutil.copytree() |
os.system("cp ...")(不推荐) |
| 移动/重命名文件/目录 | shutil.move() |
os.rename()(跨分区可能失败) |
| 批量查找文件(按模式) | pathlib.Path.glob() 或 glob.glob() |
os.listdir() + fnmatch 过滤 |
| 文件名匹配(单字符串) | fnmatch.fnmatch() |
正则表达式(re.match) |
| 压缩/解压文件 | shutil.make_archive() / shutil.unpack_archive() |
zipfile / tarfile(更底层) |
2. 最佳实践指南
-
优先使用
pathlib:
面向对象的 API 更直观,支持链式操作和属性访问(如path.parent、path.suffix),代码可读性远超os.path。 -
复杂操作依赖
shutil:
复制目录、移动跨分区文件、删除非空目录等高级操作,shutil封装了底层细节,比直接调用os更安全。 -
批量查找用
glob或pathlib.glob:
通配符模式(*.txt、**/*.py)比手动遍历过滤更高效,pathlib的glob方法可直接返回Path对象,便于后续操作。
4.** 兼容旧版本选 os + os.path**:
若需支持 Python 3.4 以下版本,os 和 os.path 是唯一选择,但需注意跨平台路径分隔符问题。
5.** 危险操作加校验 **:
- 删除文件/目录前,先用
path.exists()确认路径存在; - 使用
shutil.rmtree()时,建议添加onerror回调处理异常; - 移动/复制重要文件前,可先备份或校验文件哈希。
6.** 结合上下文管理器 **:
操作文件时优先用 with 语句(如 with open(...)),确保资源正确释放;压缩/解压可用 zipfile.ZipFile 上下文管理器。
五、总结
Python 的文件/目录操作库形成了完整的生态:os 提供底层支持,os.path 处理路径字符串,pathlib 实现现代面向对象接口,shutil 封装高级操作,glob 和 fnmatch 专注模式匹配。
实际开发中,应根据 Python 版本、操作复杂度和跨平台需求选择合适的工具:
- 简单路径处理:
pathlib一行代码搞定; - 批量文件操作:
glob+shutil组合高效便捷; - 系统级交互:
os库直接调用系统功能。
掌握这些库的用法,可轻松应对文件管理、数据处理、自动化脚本等场景,大幅提升开发效率。

浙公网安备 33010602011771号