← 返回题目列表

Python 中 shutil 和 os 处理文件有什么区别?copy、move、rmtree 使用时要注意什么?

高频 中等 第 12 / 27 题 更新于 2026/07/27
shutil文件复制文件移动目录删除

简化版

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 是高层文件操作工具,方便也危险。复制、移动、删除目录前,要先确认路径、元数据要求和失败后的恢复策略。

  • 误区:copyfilecopycopy2 没什么区别。 copyfile 只复制文件内容到目标文件,copy 还会复制权限模式,copy2 尽量保留更多元数据如修改时间。
  • 追问:move 为什么有时很快,有时很慢? 同一文件系统内通常可以重命名,速度快;跨文件系统时可能退化为复制再删除,耗时和失败风险都更高。
  • 误区:rmtree 只是删除一个普通目录。 它会递归删除整棵目录树,是高危操作;路径算错可能造成不可恢复的数据损坏。
  • 追问:复制目录时目标目录已存在怎么办? 现代 Python 的 copytree 支持 dirs_exist_ok=True 合并复制;否则目标存在会报错,面试可说明版本差异。
  • 误区:复制文件一定会保留所有元数据。 所有者、ACL、扩展属性、创建时间等不一定完整保留,跨平台差异更明显;高要求备份要用专门工具或额外校验。
  • 追问:删除前怎么降低误删风险? 使用 Path.resolve() 校验目标范围、拒绝空路径或根目录、先 dry-run 打印计划、必要时移入回收区或备份目录。

七、加强记忆

os 像底层工具箱,负责删除文件、创建目录、重命名等基础操作;shutil 像文件管理助手,负责复制、移动、目录树、归档等高层操作。面试里除了会用 API,更要说出 rmtree()、跨文件系统 move()、元数据保留这些风险点。