【第7章 I/O编程与异常】Python 路径与目录操作全解析:核心库、用法与实例

Python 文件与目录操作全解析:核心库、用法与实例

Python 提供了多个用于文件/目录操作的标准库,涵盖路径处理、文件读写、目录遍历、权限管理等核心场景。本文将系统梳理 6 个核心库osos.pathpathlibshutilglobfnmatch),从「功能定位、核心 API、实例代码、适用场景」四个维度展开,所有代码均可直接运行,兼顾基础用法与实战场景。

一、核心库概览:功能定位与选型指南

库名 核心功能 设计风格 适用场景 Python 版本要求
os 底层系统调用(目录创建/删除、进程、权限) 函数式 API 基础目录操作、系统交互 全版本支持
os.path 路径字符串处理(拼接、判断、拆分) 函数式 API 路径格式化、合法性校验(兼容 Python 2/3) 全版本支持
pathlib 面向对象的路径操作(推荐!) 类实例化 API 现代 Python 路径处理(简洁、易读) 3.4+
shutil 高级文件/目录操作(复制、移动、归档) 函数式 API 文件批量复制、目录合并、压缩解压 全版本支持
glob 路径模式匹配(通配符查找文件) 函数式 API 按文件名/后缀批量查找文件 全版本支持
fnmatch 文件名模式匹配(单独字符串匹配) 函数式 API 自定义文件名过滤规则(不依赖路径) 全版本支持

选型原则:

  1. Python 3.4+ 优先用 pathlib:面向对象设计,代码更简洁,支持链式调用;
  2. 兼容旧版本用 os + os.path:全版本支持,生态成熟;
  3. 高级操作(复制/移动/压缩)用 shutil
  4. 批量查找文件用 glob
  5. 仅文件名匹配用 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.pathos 库的子模块,专门用于路径字符串的拼接、拆分、判断等操作,兼容 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"
  • 方法封装:将 osos.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());
  • 功能更全面:整合了 osos.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.txtfileA.txt(不匹配 file10.txt
[] 匹配括号内的任意一个字符 file[1-3].txt file1.txtfile2.txtfile3.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.txtprefix_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. 最佳实践指南

  1. 优先使用 pathlib
    面向对象的 API 更直观,支持链式操作和属性访问(如 path.parentpath.suffix),代码可读性远超 os.path

  2. 复杂操作依赖 shutil
    复制目录、移动跨分区文件、删除非空目录等高级操作,shutil 封装了底层细节,比直接调用 os 更安全。

  3. 批量查找用 globpathlib.glob
    通配符模式(*.txt**/*.py)比手动遍历过滤更高效,pathlibglob 方法可直接返回 Path 对象,便于后续操作。

4.** 兼容旧版本选 os + os.path**:
若需支持 Python 3.4 以下版本,osos.path 是唯一选择,但需注意跨平台路径分隔符问题。

5.** 危险操作加校验 **:

  • 删除文件/目录前,先用 path.exists() 确认路径存在;
  • 使用 shutil.rmtree() 时,建议添加 onerror 回调处理异常;
  • 移动/复制重要文件前,可先备份或校验文件哈希。

6.** 结合上下文管理器 **:
操作文件时优先用 with 语句(如 with open(...)),确保资源正确释放;压缩/解压可用 zipfile.ZipFile 上下文管理器。

五、总结

Python 的文件/目录操作库形成了完整的生态:os 提供底层支持,os.path 处理路径字符串,pathlib 实现现代面向对象接口,shutil 封装高级操作,globfnmatch 专注模式匹配。

实际开发中,应根据 Python 版本、操作复杂度和跨平台需求选择合适的工具:

  • 简单路径处理:pathlib 一行代码搞定;
  • 批量文件操作:glob + shutil 组合高效便捷;
  • 系统级交互:os 库直接调用系统功能。

掌握这些库的用法,可轻松应对文件管理、数据处理、自动化脚本等场景,大幅提升开发效率。

posted @ 2025-11-15 21:54  wangya216  阅读(60)  评论(0)    收藏  举报