复制和合并不包括某些扩展名的目录

Copying and merging directories excluding certain extensions

我想将多个结构相同(子目录名称相同)但内容不同的目录复制到第三个位置并合并它们。同时,我想忽略某些文件扩展名而不是复制它们。


我发现 distutils.dir_util 库中的 copy_tree() 函数可以轻松处理第一个任务。这里的问题是 copy_tree() 不能忽略文件;它只是复制所有内容..

distutils.dir_util.copy_tree() - example

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.

对于第二个任务(使用排除文件的选项进行复制)这次有 shutil 库中的 copytree() 函数。现在的问题是它不能合并文件夹,因为目标目录不能存在..

shutil.copytree() - example

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..

有什么东西可以提供两全其美的东西,还是我必须自己编写代码?

如果你确实想直接使用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

正如 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)