Как скопировать содержимое двух директорий в Python
Быстрый ответ
Для копирования фаjлов и директорий с сохранением их метаданных в уже существующую директорию хорошо подходят модули shutil
и os
. Ниже приведенный код демонстрирует, как это делается:
import os, shutil
def recursive_copy(src, dst):
os.makedirs(dst, exist_ok=True)
for item in os.listdir(src):
source_item = os.path.join(src, item)
dest_item = os.path.join(dst, item)
if os.path.isdir(source_item):
recursive_copy(source_item, dest_item)
else:
shutil.copy2(source_item, dest_item)
recursive_copy('/source/dir', '/target/existing/dir')
В результате все файлы и поддиректории из /source/dir
будут перенесены в /target/existing/dir
со сохранением их исходных атрибутов.
За рамками основного: исключения и версии Python
Обходной путь для версий Python ниже 3.8
Если вы используете версию Python ниже 3.8, то может возникнуть исключение OSError
. Примените функцию copy_tree
из модуля distutils.dir_util
, чтобы избежать этой ошибки:
from distutils.dir_util import copy_tree
copy_tree('/source/dir', '/target/existing/dir') # Теперь никакие OSError не помешают!
Внимательность к символическим ссылкам и правам доступа
Необходимо учесть символические ссылки и права доступа при копировании. Все должно быть скопировано правильно:
def custom_copy(src, dst):
os.makedirs(dst, exist_ok=True)
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dst, item)
if os.path.islink(s):
linkto = os.readlink(s)
os.symlink(linkto, d)
os.lchmod(d, os.lstat(s).st_mode)
elif os.path.isdir(s):
custom_copy(s, d)
else:
shutil.copy2(s, d)
custom_copy('/source/dir', '/target/existing/dir')
Перехват ошибок на лету
Лучший способ обработать возможные ошибки — это перехватывать исключения shutil.Error
:
try:
custom_copy('/source/dir', '/target/existing/dir')
except shutil.Error as e:
print(f'Ошибка: {e}') # Python поможет определить причину ошибки
Визуализация
Предположим, что ваши папки – это полки с книгами 📚:
Вы хотите перенести свои книги (📖) на полку с мистическими сюжетами:
import shutil
shutil.copytree('/source/books', '/destination/mysteries', dirs_exist_ok=True) # Магическое действие для перемещения книг
Результат операции:
До копирования:
📚📚 Книги 📚📚 Мистика
[📖📖📖] [🔍🔍🔍]
После копирования:
📚📚 Мистика
[🔍🔍🔍📖📖📖]
Таким образом, книги (📖) были перенесены на полку с мистикой (🔍)!
Различные сценарии копирования директорий
Селективное обновление: копирование только новых файлов
Если вам требуется обновить только новые или измененные файлы, условно говоря, как повара добавляют в блюдо только недостающие специи:
import os, shutil, filecmp
def selective_copy(src, dst):
if not os.path.exists(dst) or not filecmp.cmp(src, dst, shallow=False):
shutil.copy2(src, dst)
Используйте этот метод в функции recursive_copy
, вместо стандартного shutil.copy2
.
Копирование только поддиректорий: игнорирование файлов верхнего уровня
Если необходимо скопировать только поддиректории, исключая файлы верхнего уровня, фильтруйте их таким образом:
from pathlib import Path
def dirs_only_copy(src, dst):
for item in Path(src).iterdir():
if item.is_dir():
recursive_copy(str(item), os.path.join(dst, item.name))
dirs_only_copy('/source/dir', '/target/existing/dir') # Теперь копируем только папки
Сохранение метаданных состояния файлов после копирования
Для создания точной копии including содержимого с сохранением метаданных примените shutil.copystat
:
import shutil
# После использования функции recursive_copy
shutil.copystat('/source/dir', '/target/existing/dir') # Теперь это идеальное зеркало
Полезные материалы
- shutil — Файловые операции высокого уровня — Документация Python 3.12.1
- python – Как копировать файлы – Stack Overflow
- os — Разнообразные интерфейсы операционной системы — Документация Python 3.12.1
- pathlib — Объектно-ориентированные пути файловой системы — Документация Python 3.12.1
- Глоссарий — Документация Python 3.12.1
- Управление каталогами Python – GeeksforGeeks