Копирование и объединение каталогов, исключая определенные расширения
Я хочу скопировать несколько каталогов с одинаковой структурой (подкаталоги имеют одинаковые имена), но различное содержимое в третье место и объединить их. В то же время я хочу игнорировать некоторые расширения файлов, а не копировать их.
Я обнаружил, что первая задача может быть легко обработана функцией copy_tree()
из библиотеки distutils.dir_util
. Проблема здесь в том, что copy_tree()
не может игнорировать файлы; он просто копирует все.
distutils.dir_util.copy_tree() - пример
dirs_to_copy = [r'J:\Data\Folder_A', r'J:\Data\Folder_B']
destination_dir = r'J:\Data\DestinationFolder'
for files in dirs_to_copy:
distutils.dir_util.copy_tree(files, destination_dir)
# succeeds in merging sub-directories but copies everything.
# Due to time constrains, this is not an option.
Для второй задачи (копирование с возможностью исключения файлов) на этот раз функция copytree()
из библиотеки shutil
. Проблема заключается в том, что он не может объединять папки, поскольку каталог назначения не должен существовать.
shutil.copytree() - пример
dirs_to_copy = [r'J:\Data\Folder_A', r'J:\Data\Folder_B']
destination_dir = r'J:\Data\DestinationFolder'
for files in dirs_to_copy:
shutil.copytree(files, destination_dir, ignore=shutil.ignore_patterns("*.abc"))
# successfully ignores files with "abc" extensions but fails
# at the second iteration since "Destination" folder exists..
Есть ли что-то, что обеспечивает лучшее из обоих миров, или я должен сам это кодировать?
Ответы
Ответ 1
Как сказал PeterBrittain, написать мою собственную версию shutil.copytree()
было возможным. Ниже приведен код. Обратите внимание, что единственная разница заключается в обертке os.makedirs()
в блоке if
.
from shutil import copy2, copystat, Error, ignore_patterns
import os
def copytree_multi(src, dst, symlinks=False, ignore=None):
names = os.listdir(src)
if ignore is not None:
ignored_names = ignore(src, names)
else:
ignored_names = set()
# -------- E D I T --------
# os.path.isdir(dst)
if not os.path.isdir(dst):
os.makedirs(dst)
# -------- E D I T --------
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_multi(srcname, dstname, symlinks, ignore)
else:
copy2(srcname, dstname)
except (IOError, os.error) as why:
errors.append((srcname, dstname, str(why)))
except Error as err:
errors.extend(err.args[0])
try:
copystat(src, dst)
except WindowsError:
pass
except OSError as why:
errors.extend((src, dst, str(why)))
if errors:
raise Error(errors)
Ответ 2
если вы хотите напрямую использовать shutil, вот горячий патч для os.makedirs, чтобы пропустить ошибку.
import os
os_makedirs = os.makedirs
def safe_makedirs(name, mode=0777):
if not os.path.exists(name):
os_makedirs(name, mode)
os.makedirs = safe_makedirs
import shutil
dirs_to_copy = [r'J:\Data\Folder_A', r'J:\Data\Folder_B']
destination_dir = r'J:\Data\DestinationFolder'
if os.path.exists(destination_dir):
shutil.rmtree(destination_dir)
for files in dirs_to_copy:
shutil.copytree(files, destination_dir, ignore=shutil.ignore_patterns("*.abc")) code here