Копирование файлов в Python: простые способы и лучшие практики
Зачем учиться копировать файлы в Python
Копирование файлов — простая, но важная навык для автоматизации рутинных задач. С его помощью вы можете переносить бэкапы, формировать пайплайны обработки данных и писать скрипты для развёртывания. В статье разобраны встроенные инструменты Python и их отличия: когда сохраняются метаданные, когда удобнее вызывать системную команду, а когда лучше обойтись без внешних библиотек.
Важно: при работе с реальными данными всегда проверяйте права доступа и убедитесь, что не перезаписываете важные файлы.
Основные варианты (ключевой запрос: копировать файлы в Python)
- shutil — стандартный и безопасный для большинства задач
- os / subprocess — вызывает системные команды (copy, cp, xcopy) и полезен при интеграции с shell-скриптами
- ручное чтение/запись через open(…) — гибко и не требует дополнительных модулей
Требования для копирования файлов в Python
Требования зависят от выбранного метода:
- Для shutil: модуль входит в стандартную библиотеку, импорта достаточно.
- Для os и subprocess: доступ к shell-командам (в Windows — copy/xcopy, в Linux — cp).
- При работе с двоичными файлами используйте режимы “rb” и “wb”.
Если вы копируете между разными файловыми системами или через сетевые пути, учтите ограничения прав и символических ссылок.
Как копировать файлы с помощью shutil (рекомендуется)
Модуль shutil предназначен именно для операций с файлами и папками. Он прост и переносит содержимое файла, а при использовании copy2 — также метаданные.
Простейший вызов:
import shutil
shutil.copy(src_path, dst_path) # копирует содержимое, не сохраняет метаданныеПример: копирование и переименование
import shutil
sourceFile = "C:/Users/some_directories/my_folder/copy.txt"
destinationFile = "C:/Users/some_directories/destination/newFile.txt"
shutil.copy(sourceFile, destinationFile)Сохранение метаданных (время создания/модификации, права) — используйте copy2:
import shutil
shutil.copy2(sourceFile, destinationFile)Когда удобно работать с файловыми объектами напрямую, используйте 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)copyfile — ещё одна вариация, принимающая пути:
import shutil
shutil.copyfile(sourceFilePath, destinationFilePath)Примечание: follow_symlinks — параметр, задающий поведение при символических ссылках. Используйте его, когда источником или приёмником являются символьные ссылки.
Как копировать файлы с помощью модуля os
Модуль os позволяет запускать системные команды. Это удобно, если вы хотите выполнить операцию так же, как в терминале.
Для Windows:
import os
os.system('copy source.txt destination.txt')
# или xcopy для расширенных возможностей
os.system('xcopy source.txt destination.txt')Для Linux / macOS:
import os
os.system('cp source.txt destination.txt')os.popen даёт возможность читать вывод команды:
import os
stream = os.popen('cp source.txt destination.txt')
output = stream.read()Важно: os.system/os.popen выполняют команду в shell. Передавать пользовательский ввод в командную строку напрямую небезопасно — возможны инъекции.
Как копировать файлы с помощью subprocess
subprocess даёт более точный контроль, чем os.system, и позволяет безопаснее работать с аргументами.
Пример с shell=True (используйте осторожно):
import subprocess as sp
sp.call("copy sourceFile destinationFile", shell=True) # Windows
# или
sp.call("cp sourceFile destinationFile", shell=True) # LinuxЛучше передавать аргументы как список, чтобы избежать shell-инъекций:
import subprocess as sp
sp.run(["cp", "sourceFile", "destinationFile"], check=True) # LinuxДля чтения вывода используйте check_output:
import subprocess as sp
output = sp.check_output(["cp", "sourceFile", "destinationFile"]) # обычно пустой при успешном выполненииПримечание: subprocess удобен, если нужно обработать код возврата или перехватить stderr/stdout.
Копирование без использования библиотек (через 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(source=None, destination=None):
if not (source and destination):
print("Please enter the source and destination paths")
return
with open(source, "rb") as read, open(destination, "wb") as myfile:
myfile.write(read.read())
# Пример вызова
copy_file(sourcePath, destinationPath)Этот метод прост и независим, но не сохраняет метаданные и может быть медленнее для очень больших файлов, если не выполнять разбивку на чанки.
Шпаргалка: команды и функции (Windows / Linux)
- shutil.copy(src, dst) — копирует содержимое файла
- shutil.copy2(src, dst) — копирует содержимое + метаданные
- shutil.copyfile(src, dst) — аналогичный copy для путей
- shutil.copyfileobj(src_fileobj, dst_fileobj) — копирует между файловыми объектами
- os.system(‘copy …’) / os.system(‘cp …’) — быстрый запуск shell-команд
- subprocess.run([…]) — безопасный запуск команд с аргументами
- open(…, ‘rb’) / open(…, ‘wb’) — ручное чтение/запись
Совет: для больших файлов используйте чтение по частям (read(1024*1024))
Мини-методология: как выбирать метод
- Нужны ли метаданные (время/права)? — да → shutil.copy2
- Требуется ли выполнение shell-скрипта или специфичных флагов ОС? — да → subprocess (с проверкой аргументов)
- Ограничены ли сторонними зависимостями? — да → open(…, ‘rb’)/write
- Копирование по сети/между томами? — учитывайте права и возможную потерю метаданных
Когда методы не подходят: ограничения и «когда это проваливается»
- Символические ссылки: по умолчанию операции могут либо копировать саму ссылку, либо её целевой файл; проверяйте поведение параметров.
- Права доступа: если у процесса недостаточно прав — операция завершится ошибкой.
- Перезапись: большинство функций перезаписывают целевой файл; добавьте проверки существования, если нужно избежать потерь.
- Очень большие файлы: чтение всего файла в память (read()) может привести к OOM. Используйте чтение чанками или shutil.copyfileobj.
Важно: никогда не выполняйте shell-команды с пользовательским вводом без валидации.
Чек-лист по ролям
Начинающий:
- Используйте shutil.copy для простых задач.
- Проверяйте существование пути с os.path.exists.
- Не работайте с привилегированными системными путями.
Разработчик приложений:
- Оборачивайте операции в try/except, логируйте ошибки.
- Проверяйте коды возврата subprocess.run(check=True).
- Добавьте атомарность: копируйте во временный файл, затем переименуйте.
Системный администратор / DevOps:
- Для больших объёмов данных используйте системные утилиты с нужными флагами (rsync, xcopy) и контролируйте права.
- Настройте мониторинг ошибок и оповещения.
Критерии приёмки
- Файл существует в целевой директории после выполнения.
- Размер и контрольная сумма (например, md5/sha256) совпадают с исходником.
- При необходимости метаданные (дата/права) сохранены.
- Процесс корректно обрабатывает ошибки и возвращает понятные сообщения.
Примеры тестов / приемочные тест-кейсы
- Копирование маленького текстового файла — ожидается идентичное содержимое.
- Копирование большого файла (несколько ГБ) с чтением чанками — процесс не падает по памяти.
- Копирование файла в папку, где файл уже есть — проверка поведения (перезапись/ошибка).
- Копирование с недостаточными правами — ожидается исключение с информативным логом.
Безопасность и приватность
- Не передавайте необработанные пути в subprocess с shell=True.
- При работе с конфиденциальными файлами ограничьте права доступа к временным файлам.
- Логи не должны содержать чувствительные данные путей/имён файлов.
Глоссарий (одна строка)
- Метаданные — служебная информация о файле: дата создания/модификации, права доступа.
- Символическая ссылка — ярлык на другой файл или каталог в файловой системе.
- Чанк — часть файла, используемая при поэтапном чтении/записи.
Резюме
Копирование файлов в Python можно выполнить несколькими способами. Для большинства задач рекомендуется shutil за простоту и переносимость. subprocess и os полезны, когда нужна интеграция с shell, а ручное чтение/запись через open даёт полную контроль и независимость от библиотек. Выбирайте метод исходя из требований к метаданным, производительности и безопасности.
Важно: тестируйте сценарии с перезаписью и ограниченными правами, чтобы избежать потерь данных.