跳到正文
效率工具实用笔记关于本站
文件整理

copytree目标目录已存在怎么办:dirs_exist_ok与ignore_patterns怎么配合

约 8 分钟阅读AI 辅助整理

copytree默认在目标目录已存在时抛FileExistsError;传dirs_exist_ok=True可继续复制并覆盖同名文件。ignore_patterns按glob模式生成忽略回调,每个被访问目录调用一次。

本文要点

  1. 把 dirs_exist_ok 设为 True,报错条件就解除了

  2. ignore_patterns 不是直接过滤文件,它返回一个函数,这个函数交给 copytree 的 ignore 参数使用

  3. ignore_patterns 接收的是 glob 风格模式,匹配对象是目录里的名字

copytree目标目录已存在怎么办:dirs_exist_ok与ignore_patterns怎么配合的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先判断报错来自哪一步:目标已存在还是复制中途出错

如果你在练习目录里运行 copytree 时看到 FileExistsError,先分清它出现在哪个阶段。

按 Python 官方 shutil 文档,copytree 的 dirs_exist_ok 参数默认是 False。当它为 False 且 dst 已经存在时,会抛出 FileExistsError。这是复制开始前就发生的判断,不是复制到一半才出的问题。

所以排查顺序是:先看报错类型是不是 FileExistsError,再看 dst 这个路径是不是已经存在。如果目标目录本来就在,报错属于预期行为,不是源目录有问题。

一个自建情境(示例,不是对真实项目的记录):在练习目录 exercise/ 下建 src_demo/ 和 dst_demo/ 两个目录,先手动建好 dst_demo/,再运行 copytree('exercise/src_demo', 'exercise/dst_demo')。这时会得到 FileExistsError。动手前建议把练习目录单独放,不要拿正在用的目录直接试。

dirs_exist_ok=True 改变的是什么:继续复制并覆盖同名文件

把 dirs_exist_ok 设为 True,报错条件就解除了。按文档说明,此时复制操作遇到已存在的目录会继续,dst 目录树中的文件会被 src 目录树中对应的文件覆盖。

这里要抓住两点。第一,它解除的是“目标目录已存在”这个前置拦截,不是解除所有错误。第二,覆盖发生在文件层面:src 里有同名文件,dst 里那份会被替换。

文档没有说明 dirs_exist_ok=True 会删除 dst 里多出来的文件。所以不要把“继续复制”理解成“让 dst 和 src 完全一致”。dst 中 src 没有的文件,按资料没有写会被删除,本文也不补这个结论。

自建示例(练习数据):

from shutil import copytree

copytree(
    'exercise/src_demo',
    'exercise/dst_demo',
    dirs_exist_ok=True,
)

运行前先确认 dst_demo 里没有你需要保留的旧文件,因为同名文件会被覆盖。

ignore_patterns 生成的是什么:一个按目录调用的回调

ignore_patterns 不是直接过滤文件,它返回一个函数,这个函数交给 copytree 的 ignore 参数使用。

按文档说明,ignore_patterns(*patterns) 是一个工厂函数,创建一个可调用对象,用作 copytree 的 ignore 参数,忽略匹配所给 glob 风格模式的文件和目录。

ignore 回调的调用方式也有明确规定:copytree 递归复制时,每访问一个目录就调用一次这个回调,传入两个参数——正在访问的目录,以及该目录内容列表(由 os.listdir 返回)。回调必须返回一组相对于当前目录的文件名和目录名,这些名字会在复制中被忽略。

所以 ignore_patterns 的工作方式是:你给它模式,它生成一个回调;copytree 每进一个目录就问一次这个回调“这里哪些名字要跳过”。

模式怎么写:glob 风格,匹配的是名字不是完整路径

ignore_patterns 接收的是 glob 风格模式,匹配对象是目录里的名字。

官方文档给的例子是:

from shutil import copytree, ignore_patterns

copytree(
    source,
    destination,
    ignore=ignore_patterns('*.pyc', 'tmp*'),
)

文档对这个例子的说明是:复制除 .pyc 文件和名字以 tmp 开头的文件或目录之外的所有内容。

从这句说明能确认两件事。第一,模式可以同时匹配文件和目录,tmp* 既可能命中文件也可能命中目录。第二,模式按名字匹配,不是按从源根目录算起的完整路径匹配。

一个自建练习(示例):在 exercise/src_demo/ 下放 a.pyc、keep.txt、tmp_note.txt 三个文件,用上面的 ignore_patterns('*.pyc', 'tmp*') 复制到 exercise/dst_demo/。按文档描述,dst_demo 里应只剩 keep.txt。这是按文档规则推演的练习,不是对某台机器的实测记录。

两个参数一起用:先过忽略回调,再决定是否覆盖

dirs_exist_ok 和 ignore 管的是两件不同的事,可以同时传。

dirs_exist_ok 管的是“目标目录已存在时要不要继续”,ignore 管的是“源目录里哪些名字不参与复制”。两者不冲突:先由 ignore 回调决定每个目录里跳过哪些名字,剩下的内容再按 dirs_exist_ok 的设定处理目标已存在的情况。

自建示例(练习数据):

from shutil import copytree, ignore_patterns

copytree(
    'exercise/src_demo',
    'exercise/dst_demo',
    dirs_exist_ok=True,
    ignore=ignore_patterns('*.pyc', 'tmp*'),
)

这段代码的含义是:dst_demo 已存在也继续复制;src_demo 里的 .pyc 文件和 tmp 开头的名字不复制;其余同名文件覆盖 dst_demo 里的对应文件。

检查结果时,可以对照两件事:dst_demo 里有没有出现本应被忽略的名字;src_demo 和 dst_demo 同名的文件,内容是不是 src 那一份。

出错时先看 Error 里的三元组,再回头核对参数

如果复制过程中出现异常,文档说明 copytree 会抛出 Error,其参数是一个列表,列表里每项是 (srcname, dstname, exception) 这样的三元组。

排查时按这个结构读:先看 srcname 和 dstname 指向哪一对路径,再看 exception 是什么类型。这样能分清问题出在某个具体文件上,还是出在参数设置上。

两个常见方向:

1. 报 FileExistsError 且没有传 dirs_exist_ok=True,说明目标目录已存在这个前置条件没处理。

2. 某个文件没被复制,先确认它的名字是否被 ignore_patterns 的模式命中。

文档还提到,如果 symlinks 为 false 且符号链接指向的文件不存在,异常会被加入 Error 列表;ignore_dangling_symlinks 设为 true 可以消除这个异常。这一点只在你处理符号链接时相关,普通文件复制不涉及。

本文只讲目标目录已存在时的报错条件、dirs_exist_ok 的作用和 ignore_patterns 生成回调的方式,不涉及删除策略,也不涉及其他文件操作函数。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回文件整理 →