shutil.copytree() 复制大型目录时可能卡住或爆内存,因默认调用 shutil.copy2 并频繁执行 copystat;建议显式指定 copy_function=shutil.copy、dirs_exist_ok=true,并配合 ignore 过滤或手动修复权限。

shutil.copytree() 会卡住或爆内存?先关掉默认的元数据复制
默认调用 shutil.copytree() 复制大型目录时,它会逐个调用 shutil.copystat() 拷贝权限、时间戳、扩展属性等元数据。对成千上万个文件来说,这不仅慢,还可能因系统调用频繁或 SELinux/xattr 不兼容导致卡死或报错(比如 OSError: [Errno 95] Operation not supported)。
实操建议:
- 显式传入
copy_function=shutil.copy(而非默认的shutil.copy2),跳过copystat - 加上
dirs_exist_ok=True(Python 3.8+),避免目标目录已存在时报错 - 若需保留部分元数据(如权限),改用
shutil.copy+ 手动os.chmod控制粒度
shutil.copytree(
src="/data/large_project",
dst="/backup/large_project",
copy_function=shutil.copy,
dirs_exist_ok=True
)
遇到“Permission denied”或“Read-only file system”怎么办?绕过 shutil 的权限检查逻辑
shutil.copytree() 在创建子目录时会尝试复现源目录的权限位(如 0o400)。如果目标文件系统不支持某些权限(如 FAT32、某些 NFS 挂载点),或当前用户无权设置该 mode,就会中断并抛出 PermissionError。
实操建议:
- 用
ignore=shutil.ignore_patterns('.git', '__pycache__')过滤掉高权限/特殊目录,减少触发点 - 自定义
ignore函数,在os.makedirs(dst, mode=...)前强制设为安全 mode(如0o755) - 更稳妥的做法:先用
shutil.copytree(..., copy_function=shutil.copy)复制内容,再用os.walk()单独批量修复关键目录权限
想边复制边看进度?别 monkey patch shutil,用 os.walk + 自定义循环
shutil.copytree() 是原子操作,不提供回调或进度钩子。强行在内部函数里插桩(比如 patch shutil.copy)容易破坏异常处理路径,尤其在大文件 IO 中断时难以清理临时状态。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
实操建议:
- 用
os.walk(src)遍历,手动os.makedirs(dst_subdir, exist_ok=True) - 对每个文件,用
shutil.copyfileobj()分块读写(控制 buffer size,如8192),并在每次 write 后更新计数器 - 配合
tqdm或简单print(f"{done}/{total} files")输出,避免频繁刷屏影响性能
for root, dirs, files in os.walk(src):
rel = os.path.relpath(root, src)
dst_root = os.path.join(dst, rel)
os.makedirs(dst_root, exist_ok=True)
for f in files:
src_f = os.path.join(root, f)
dst_f = os.path.join(dst_root, f)
with open(src_f, "rb") as s, open(dst_f, "wb") as d:
shutil.copyfileobj(s, d, length=65536) # 64KB buffer
Windows 上复制超长路径失败?必须提前启用长路径支持
Windows 默认限制路径长度为 260 字符,shutil.copytree() 在遍历时遇到 \? 前缀缺失的深层嵌套路径会直接报 FileNotFoundError 或 OSError: [WinError 206],且错误信息不提示根本原因。
实操建议:
- 确认系统已启用长路径:注册表项
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlFileSystemLongPathsEnabled值为1 - Python 启动前设置环境变量
set PYTHONIOENCODING=utf-8,避免路径 decode 失败 - 代码中对路径做预检:
if len(os.path.abspath(path)) > 240:提前 warn,而不是等 copytree 报错
真正麻烦的是跨平台脚本——Linux/macOS 下没问题的路径,在 Windows CI 环境里静默失败。这点很容易被忽略,直到备份任务在生产机上卡住。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










