Как рекурсивно копировать каталог в python и перезаписывать все?
Я пытаюсь скопировать /home/myUser/dir1/
и все его содержимое (и их содержимое и т.д.) в /home/myuser/dir2/
в python. Кроме того, я хочу, чтобы копия перезаписывала все в dir2/
.
Похоже, что distutils.dir_util.copy_tree
может быть правильным инструментом для задания, но не уверен, что для такой простой задачи есть что-то более простое/более очевидное.
Если это правильный инструмент, как его использовать? Согласно docs имеется 8 параметров. Мне нужно передать все 8 только src
, dst
и update
, и если да, то как (я новичок в Python).
Если что-то там лучше, может ли кто-нибудь дать мне пример и указать мне в правильном направлении? Спасибо заранее!
Ответы
Ответ 1
Вы можете использовать distutils.dir_util.copy_tree
. Он работает нормально, и вам не нужно передавать каждый аргумент, только src
и dst
являются обязательными.
Однако в вашем случае вы не можете использовать аналогичный инструмент, например shutil.copytree
, потому что он ведет себя по-другому: поскольку каталог назначения не должен существовать, эта функция не может использоваться для перезаписи его содержимого.
Если вы хотите использовать инструмент cp
, как предложено в комментариях к вопросу, остерегайтесь, что использование модуля subprocess
в настоящее время является рекомендуемым способом для нереста новых процессов, как вы можете видеть в документация функции os.system.
Ответ 2
Взгляните на пакет shutil
, особенно rmtree
и copytree
. Вы можете проверить, существует ли файл/путь с помощью os.paths.exists(<path>)
.
import shutil
import os
def copy_and_overwrite(from_path, to_path):
if os.path.exists(to_path):
shutil.rmtree(to_path)
shutil.copytree(from_path, to_path)
Винсент был прав, что copytree
не работает, если каталоги уже существуют. Так что distutils
- лучшая версия. Ниже приведена исправленная версия shutil.copytree
. Он в основном скопировал 1-1, кроме первого os.makedirs()
, помещенного за конструкцией if-else:
import os
from shutil import *
def copytree(src, dst, symlinks=False, ignore=None):
names = os.listdir(src)
if ignore is not None:
ignored_names = ignore(src, names)
else:
ignored_names = set()
if not os.path.isdir(dst): # This one line does the trick
os.makedirs(dst)
errors = []
for name in names:
if name in ignored_names:
continue
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
try:
if symlinks and os.path.islink(srcname):
linkto = os.readlink(srcname)
os.symlink(linkto, dstname)
elif os.path.isdir(srcname):
copytree(srcname, dstname, symlinks, ignore)
else:
# Will raise a SpecialFileError for unsupported file types
copy2(srcname, dstname)
# catch the Error from the recursive copytree so that we can
# continue with other files
except Error, err:
errors.extend(err.args[0])
except EnvironmentError, why:
errors.append((srcname, dstname, str(why)))
try:
copystat(src, dst)
except OSError, why:
if WindowsError is not None and isinstance(why, WindowsError):
# Copying file access times may fail on Windows
pass
else:
errors.extend((src, dst, str(why)))
if errors:
raise Error, errors
Ответ 3
Здесь простое решение для рекурсивной перезаписи адресата с источником, создающего все необходимые каталоги по мере его появления. Это не обрабатывает символические ссылки, но это будет простое расширение (см. Ответ от @Michael выше).
def recursive_overwrite(src, dest, ignore=None):
if os.path.isdir(src):
if not os.path.isdir(dest):
os.makedirs(dest)
files = os.listdir(src)
if ignore is not None:
ignored = ignore(src, files)
else:
ignored = set()
for f in files:
if f not in ignored:
recursive_overwrite(os.path.join(src, f),
os.path.join(dest, f),
ignore)
else:
shutil.copyfile(src, dest)
Ответ 4
Вот решение, которое помогло мне в нескольких строках кода:
def overwrite(dir_src, dir_dst):
for root, dirs, files in os.walk(dir_src):
for filename in files:
file_path_src = os.path.join(root, filename)
# replace the first occurrence of lambdas_src_folder with tmp_folder
file_path_dst = file_path_src.replace(dir_src, dir_dst, 1)
# overwrite or create file (https://docs.python.org/2/library/shutil.html#shutil.copy)
shutil.copy(file_path_src, file_path_dst)