Python shutil.copytree: скопировать папку с файлами

Категория: Python · Язык: Python · Обновлено:

shutil.copytree() рекурсивно копирует каталог вместе с вложенными файлами и возвращает путь назначения. По умолчанию целевая папка не должна существовать: при наличии выбрасывается FileExistsError. Параметр dirs_exist_ok=True (Python 3.8+) разрешает слияние с существующим каталогом.

Скопировать папку и исключить кэш

Python
import shutil
from pathlib import Path

src = Path("src")
dst = Path("backup")
src.mkdir(exist_ok=True)
(src / "app.py").write_text("print('ok')\n", encoding="utf-8")

shutil.copytree(
    src,
    dst,
    ignore=shutil.ignore_patterns("*.pyc", "__pycache__"),
)
print((dst / "app.py").read_text(encoding="utf-8").strip())  # print('ok')

ignore_patterns создаёт функцию для аргумента ignore; она получает каталог и список имён и возвращает то, что нужно пропустить. Шаблоны проверяются по именам, а не по полным путям. Для более сложной фильтрации напишите свою функцию и передайте её в ignore.

copytree по умолчанию использует copy2, поэтому сохраняет время изменения и права доступа. Символические ссылки по умолчанию разыменовываются; symlinks=True копирует саму ссылку. Жёсткие ссылки не сохраняются: каждый файл получает отдельную копию. Для больших деревьев это может удвоить место.

Слить с существующим каталогом

Python
import shutil

shutil.copytree("src", "backup", dirs_exist_ok=True)
print("слияние завершено")  # слияние завершено

dirs_exist_ok=True не удаляет лишние файлы в приёмнике: он перезаписывает совпавшие и добавляет новые. Если нужна точная копия без старых файлов, сначала удалите каталог или используйте dirsync из сторонней библиотеки. Будьте осторожны с правами: при слиянии файлы приёмника могут остаться от предыдущей версии.

Функция работает только с локальной файловой системой и не подходит для сетевых URL, S3 или архивов. Для копирования по сети используйте rsync, для облака — SDK провайдера. При копировании в цикле проверяйте свободное место и обрабатывайте OSError: частично скопированное дерево останется на диске.

Документация: shutil.copytree, shutil.ignore_patterns.