Python 移动 / 复制目录的正确写法:shutil 全场景速查

Python 里”移动整个目录”或”把文件全复制到另一处”这类操作,全部靠 shutil。列几个最常用的模板。

移动整个目录

99% 场景直接:

import shutil

shutil.move(r"C:\source_dir", r"D:\target_dir")

行为:

  • 目标不存在 → 直接改名/移动
  • 目标已存在 → 源被移到 目标\源目录名
  • 同盘 是秒移(本质是 rename)
  • 跨盘 会退化成复制 + 删除

想强制覆盖已有目标:

import os, shutil

src = r"C:\source_dir"
dst = r"D:\target_dir\source_dir"

if os.path.exists(dst):
    shutil.rmtree(dst)
shutil.move(src, dst)

复制整个目录(含子目录)

Python 3.8+:

import shutil

shutil.copytree(
    r"C:\source_dir",
    r"D:\target_dir",
    dirs_exist_ok=True,   # 目标已存在时合并写入
)

会连带子目录、文件属性一起复制。

只复制当前目录里的文件(跳过子目录)

import os, shutil

src = r"C:\source_dir"
dst = r"D:\target_dir"
os.makedirs(dst, exist_ok=True)

for name in os.listdir(src):
    s = os.path.join(src, name)
    if os.path.isfile(s):
        shutil.copy2(s, os.path.join(dst, name))

copy2 会保留 mtime、权限,比 copy 更完整。

只复制某类文件

import os, shutil

for name in os.listdir(src):
    if name.endswith(".txt"):
        shutil.copy2(
            os.path.join(src, name),
            os.path.join(dst, name),
        )

递归复制文件(扁平化,不保留目录结构)

import os, shutil

for root, _, files in os.walk(src):
    for f in files:
        shutil.copy2(os.path.join(root, f), os.path.join(dst, f))

注意同名文件会互相覆盖,要保结构就直接 copytree

pathlib 版本(更现代)

from pathlib import Path
import shutil

src = Path(r"D:\A\deep\folder")
dst = Path(r"D:\B\deep\folder")

if dst.exists():
    shutil.rmtree(dst)
dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copytree(src, dst)

Pathparent / mkdir(parents=True) 组合特别适合处理”目标父目录还没创建”的情况。

不要用 os.rename

os.rename(src, dst)
  • 跨磁盘直接报错
  • 不能覆盖已有目录

除非明确是”同盘、无冲突”,否则直接上 shutil.move

一句话总结

移动用 shutil.move,整目录复制用 shutil.copytree(dirs_exist_ok=True)。其它场景在这两个基础上按需组合。