Python 中 shutil 和 os 处理文件有什么区别?copy、move、rmtree 使用时要注意什么?
简化版
os 更偏底层系统调用和路径、权限、重命名等基础操作;shutil 更偏高层文件和目录操作,比如复制、移动、删除目录树、打包归档。使用 shutil.rmtree() 删除目录树要非常谨慎,删除前必须确认目标路径。
详细版
常见操作:
import shutil
shutil.copyfile("a.txt", "b.txt") # 复制文件内容
shutil.copy("a.txt", "dir/") # 复制文件内容和权限到目录或文件
shutil.copy2("a.txt", "dir/") # 尽量保留更多元数据
shutil.copytree("src", "dst") # 复制目录树
shutil.move("old.txt", "new.txt") # 移动或重命名
shutil.rmtree("build") # 删除整个目录树
和 os 的关系:
os.remove()删除文件;os.rmdir()删除空目录;os.rename()/os.replace()重命名或替换;shutil封装了更高层的复制、移动、目录树操作。
面试回答要体现风险意识:rmtree() 是递归删除,不能对不确定路径、用户输入路径、项目根目录随便调用。删除前应做路径解析和范围校验。
完整版教学
一、os 和 shutil 的定位不同
os 模块提供大量操作系统相关能力,文件部分更接近基础操作:
import os
os.remove("a.txt")
os.rename("a.txt", "b.txt")
os.mkdir("logs")
shutil 的名字来自 shell utilities,提供更像命令行工具的高层文件操作:
import shutil
shutil.copy("a.txt", "backup/")
shutil.move("backup/a.txt", "archive/a.txt")
简单说:os 更基础,shutil 更方便。
二、copyfile、copy、copy2 的区别
copyfile(src, dst) 只复制文件内容,目标必须是文件路径:
shutil.copyfile("a.txt", "b.txt")
copy(src, dst) 可以把文件复制到目录,并会复制权限模式:
shutil.copy("a.txt", "backup/")
copy2(src, dst) 会尝试复制更多元数据,比如访问时间、修改时间等:
shutil.copy2("a.txt", "backup/")
注意“尽量保留元数据”不代表所有平台都能完整保留所有文件属性。跨文件系统、跨平台时,权限、所有者、扩展属性等可能有差异。
三、copytree 复制目录树
复制整个目录可以用:
shutil.copytree("src_dir", "dst_dir")
默认情况下,目标目录已存在时会报错。现代 Python 支持通过参数控制已存在目录的行为,但面试中重点不在背参数,而在知道它是递归复制目录树,可能涉及大量文件,应该注意:
- 目标目录是否已存在;
- 是否要忽略某些文件;
- 是否会复制隐藏文件、缓存文件、大文件;
- 磁盘空间是否足够。
四、move 可能是重命名,也可能是复制加删除
shutil.move() 在同一文件系统内通常可以近似理解为重命名;跨文件系统时,可能退化为复制后删除源文件。
这意味着移动大文件到另一个磁盘可能并不快,也可能在复制成功但删除失败时留下源文件。对关键数据迁移,要设计校验和回滚策略,不能只靠一行 move()。
五、rmtree 是高危操作
shutil.rmtree(path) 会递归删除整个目录树:
shutil.rmtree("dist")
这类 API 在清理构建目录时很方便,但也很危险。如果路径变量算错,可能删除大量重要文件。
更稳妥的思路是:
from pathlib import Path
import shutil
root = Path("work").resolve()
target = (root / "tmp-build").resolve()
if root in target.parents and target.name.startswith("tmp-"):
shutil.rmtree(target)
else:
raise ValueError("refuse to delete unsafe path")
删除前做路径解析、范围校验和命名约束,是成熟工程习惯。
六、常见误区与追问
心法:
shutil是高层文件操作工具,方便也危险。复制、移动、删除目录前,要先确认路径、元数据要求和失败后的恢复策略。
- 误区:
copyfile、copy、copy2没什么区别。copyfile只复制文件内容到目标文件,copy还会复制权限模式,copy2尽量保留更多元数据如修改时间。 - 追问:
move为什么有时很快,有时很慢? 同一文件系统内通常可以重命名,速度快;跨文件系统时可能退化为复制再删除,耗时和失败风险都更高。 - 误区:
rmtree只是删除一个普通目录。 它会递归删除整棵目录树,是高危操作;路径算错可能造成不可恢复的数据损坏。 - 追问:复制目录时目标目录已存在怎么办? 现代 Python 的
copytree支持dirs_exist_ok=True合并复制;否则目标存在会报错,面试可说明版本差异。 - 误区:复制文件一定会保留所有元数据。 所有者、ACL、扩展属性、创建时间等不一定完整保留,跨平台差异更明显;高要求备份要用专门工具或额外校验。
- 追问:删除前怎么降低误删风险? 使用
Path.resolve()校验目标范围、拒绝空路径或根目录、先 dry-run 打印计划、必要时移入回收区或备份目录。
七、加强记忆
os 像底层工具箱,负责删除文件、创建目录、重命名等基础操作;shutil 像文件管理助手,负责复制、移动、目录树、归档等高层操作。面试里除了会用 API,更要说出 rmtree()、跨文件系统 move()、元数据保留这些风险点。