Как копировать файлы в Python

Зачем учиться копировать файлы в Python
Копирование файлов — простая и полезная операция, которая часто встречается в автоматизации задач: резервное копирование, подготовка тестовых данных, миграция логов и т. п. Освоив базовые методы, вы сможете создавать надёжные скрипты и избегать распространённых ошибок (повторная запись, потеря метаданных, проблемы с правами доступа).
Краткое определение: “метаданные” — это атрибуты файла (время модификации, права доступа и т. п.).
Требования для копирования файлов в Python
- Самый простой и надёжный путь — встроенная библиотека shutil (не требует установки сторонних пакетов).
- Для системных вызовов пригодятся os и subprocess.
- Для чтения/записи “вручную” достаточно стандартной функции open().
- Права доступа: убедитесь, что ваш процесс имеет чтение исходного файла и запись в папку назначения.
- На разных ОС команды и поведение могут отличаться (Windows: copy, xcopy; Linux/macOS: cp).
Совет: используйте абсолютные пути или проверяйте текущую рабочую директорию перед операцией (os.getcwd()).
Копирование файлов с помощью shutil (рекомендуемый способ)
Модуль shutil — встроенный, простой и функциональный. Он предоставляет несколько функций для разных потребностей:
- shutil.copy(src, dst) — копирует содержимое файла; метаданные не сохраняются.
- shutil.copy2(src, dst) — копирует содержимое и метаданные (атрибуты файла).
- shutil.copyfile(src, dst) — как copy, но требует, чтобы dst был путём к файлу (не папке).
- shutil.copyfileobj(fsrc, fdst) — копирует между файловыми объектами (позволяет контролировать буфер).
Пример использования shutil.copy:
import shutil
sourceFile = "C:/Users/some_directories/my_folder/copy.txt"
destinationFile = "C:/Users/some_directories/destination/newFile.txt"
shutil.copy(sourceFile, destinationFile, follow_symlinks=True)Если нужно также сохранить метаданные (время создания/модификации, права), используйте copy2:
import shutil
shutil.copy2(sourceFile, destinationFile, follow_symlinks=True)Когда использовать copyfileobj — пример поблочного копирования (полезно при больших файлах):
import shutil
with open("C:/Users/some_directories/my_folder/copy.txt", "rb") as src, \
open("C:/Users/some_directories/destination/newFile.txt", "wb") as dst:
shutil.copyfileobj(src, dst)Примечание: follow_symlinks=True указывает следовать символическим ссылкам. Если вы работаете в одной рабочей директории и не используете ссылки, аргумент можно опустить.
Копирование с помощью модуля os
Модуль os позволяет запускать команды оболочки через os.system() или os.popen(). Это простой, но менее переносимый метод — команды зависят от ОС.
Пример для Windows (copy):
import os
os.system('copy source.txt destination.txt')Пример для Linux/macOS (cp):
import os
os.system('cp source.txt destination.txt')os.popen похож на os.system, но возвращает файловый объект с выводом команды:
import os
stream = os.popen('cp source.txt destination.txt')
print(stream.read())Ограничения:
- Команды выполняются в оболочке, поэтому возможны риски инъекций, если вы подставляете переменные без экранирования.
- Поведение зависит от текущей рабочей директории.
Копирование с помощью subprocess
subprocess даёт более явный контроль над выполнением внешних команд и над ошибками.
Пример для Windows:
import subprocess as sp
sp.call("copy sourceFile destinationFile", shell=True)Пример для Linux/macOS:
import subprocess as sp
sp.call("cp sourceFile destinationFile", shell=True)Более современный и безопасный вариант — использовать list-формат и отключать shell=True (если возможно):
import subprocess as sp
sp.run(["cp", "sourceFile", "destinationFile"], check=True)Преимущества subprocess:
- Контроль возвратных кодов, ошибок и вывода.
- Меньше риск инъекций при использовании списка аргументов.
Копирование без библиотек (чистая реализация через open)
Иногда полезно понимать, как работает копирование “вручную” — это даёт контроль над буфером, прогрессом и обработкой ошибок.
Пример простого копирования:
sourcePath = "C:/Users/source_directories/my_folder/copy.txt"
destinationPath = "C:/Users/some_directories/destination_directories/newFile.txt"
with open(sourcePath, "rb") as read:
with open(destinationPath, "wb") as myfile:
myfile.write(read.read())Реализация с буфером для больших файлов:
def copy_file_buffered(src, dst, buf_size=16*1024):
with open(src, 'rb') as fsrc:
with open(dst, 'wb') as fdst:
while True:
buf = fsrc.read(buf_size)
if not buf:
break
fdst.write(buf)Функция-обёртка с базовой валидацией:
def copyFile(source=None, destination=None):
if not (source and destination):
print("Пожалуйста, укажите пути source и destination")
return
try:
with open(source, "rb") as read:
with open(destination, "wb") as myfile:
myfile.write(read.read())
except Exception as e:
print("Ошибка при копировании:", e)
# Пример вызова
# copyFile(sourcePath, destinationPath)Безопасность и права доступа
- Всегда проверяйте права на чтение исходного файла и запись в папку назначения.
- Не выполняйте shell-команды с неподготовленными строками, полученными от пользователя — возможна команда-инъекция.
- Для временных файлов используйте модуль tempfile и безопасные функции создания временных имён.
- При копировании конфиденциальных данных убедитесь, что файлы временно не остаются с глобальными правами (chmod).
Когда методы не подходят (ограничения и контрпримеры)
- Если нужно копировать между удалёнными машинами, shutil и open подходят только при доступе к смонтированной файловой системе. Для SFTP/FTP/HTTP используйте paramiko, ftplib или requests.
- Для атомарной замены файла применяйте временный файл + os.replace(), чтобы избежать состояния гонки.
- При копировании больших объёмов данных лучше использовать потоковую передачу с контролем скорости и проверкой контрольной суммы (hashlib).
Пример атомарной записи:
import os
import tempfile
def atomic_copy(src, dst):
dstdir = os.path.dirname(dst)
with tempfile.NamedTemporaryFile(dir=dstdir, delete=False) as tmp:
with open(src, 'rb') as fsrc:
tmp.write(fsrc.read())
os.replace(tmp.name, dst)Альтернативные подходы
- Для сетевого копирования: rsync (внешняя утилита), paramiko (SFTP), smbprotocol (SMB/CIFS).
- Для бинарной сериализации больших структур — использовать базы данных или object storage (S3) вместо файловой системы.
- Для асинхронных операций в приложениях с высокой нагрузкой — asyncio + aiofiles (библиотека).
Ментальные модели и эвристики
- “Принцип единой ответственности”: функция должна делать одну вещь — копировать, логировать или проверять права, но не всё одновременно.
- “Сначала проверь, потом действуй”: проверяйте доступ и свободное место перед большим копированием.
- “Не доверяй данным извне”: экранируйте имена файлов и пути, особенно если они приходят из сети.
Роли и чек-листы (что проверить перед применением скрипта)
Для разработчика:
- Проверить пути (абсолютные/относительные).
- Добавить обработку исключений и логирование.
- Написать unit-тесты на мелкие сценарии.
Для администратора:
- Убедиться в правах пользователя на чтение/запись.
- При необходимости настроить резервирование и мониторинг.
Для тестировщика:
- Проверить поведение при отсутствующем исходном файле.
- Проверить поведение при отсутствии места на диске.
- Проверить атомарность (замена файла во время чтения).
Сниппеты и шпаргалка (быстрый доступ)
Копирование и сохранение метаданных:
import shutil
shutil.copy2('src.txt', 'dst.txt')Копирование с проверкой ошибок:
import shutil
import os
try:
shutil.copy('src.txt', 'dst.txt')
except IOError as e:
print('I/O error:', e)
except Exception as e:
print('Ошибка:', e)Проверка свободного места (пример для POSIX):
import shutil
total, used, free = shutil.disk_usage("/")
print("Свободно:", free)Критерии приёмки
- Файл успешно копируется в целевую папку при корректных путях и правах.
- Метаданные сохраняются при использовании copy2.
- В случае ошибки — функция возвращает информативное сообщение и не оставляет частично записанных файлов (при необходимости используется атомарная замена).
- Для большого файла используется буфер, и операция не потребляет всю память.
Краткая справка (глоссарий)
- shutil — модуль для операций высокого уровня с файлами и директориями.
- os — модуль для взаимодействия с операционной системой.
- subprocess — модуль для запуска внешних процессов.
- метаданные — атрибуты файла (время, права и т. п.).
Итог и рекомендации
- Если копируете файлы локально — используйте shutil (copy или copy2 в зависимости от потребности в метаданных).
- Для вызова системных команд предпочитайте subprocess с явным списком аргументов.
- Для сетевых копий и специальных протоколов применяйте соответствующие библиотеки (paramiko, boto3 для S3 и т. п.).
- Всегда учитывайте безопасность: права доступа, проверку входных данных и атомарность операций.
Важно: практикуйтесь на тестовых данных и добавляйте логирование — это упростит диагностику проблем в проде.
Похожие материалы
Как попросить рекомендацию при поиске работы
Как быстро и эффективно писать деловые письма
Покупательская персона: руководство и шаблон
Как создать инфографику в Adobe Illustrator
Как построить профессиональную сеть в Facebook