使用shutil.copytree时过滤目录?

问题描述 投票:0回答:5

有没有办法可以使用目录的绝对路径来过滤目录?

shutil.copytree(directory,
                target_dir,
                ignore = shutil.ignore_patterns("/Full/Path/To/aDir/Common")) 

当尝试过滤位于“

aDir
”下的“公共”目录时,这似乎不起作用。如果我这样做:

shutil.copytree(directory,
                target_dir,
                ignore = shutil.ignore_patterns("Common"))

它可以工作,但是每个名为 Common 的目录都会在该“树”中被过滤,这不是我想要的。

有什么建议吗?

谢谢。

python shutil copytree
5个回答
17
投票

您可以制作自己的忽略功能:

shutil.copytree('/Full/Path', 'target',
              ignore=lambda directory, contents: ['Common'] if directory == '/Full/Path/To/aDir' else [])

或者,如果您希望能够使用相对路径调用

copytree

import os.path
def ignorePath(path):
  def ignoref(directory, contents):
    return (
        f for f in contents
        if os.path.abspath(os.path.join(directory, f)) == path)
  return ignoref

shutil.copytree('Path', 'target', ignore=ignorePath('/Full/Path/To/aDir/Common'))

来自文档:

如果给出了ignore,它必须是一个可调用的,将作为其接收 参数是 copytree() 正在访问的目录及其列表 内容,由 os.listdir() 返回。由于调用了 copytree() 递归地,忽略可调用函数将为每个调用一次 复制的目录。可调用对象必须返回一个序列 相对于当前目录的目录和文件名(即 第二个参数中的项目子集);这些名字将是 在复制过程中被忽略。 ignore_patterns() 可用于创建 这样的可调用函数会忽略基于全局样式模式的名称。


4
投票

shutil.ignore_patterns() 的 API 不支持绝对路径,但推出自己的变体非常容易。

作为起点,请查看 *ignore_patterns* 的源代码:

def ignore_patterns(*patterns):
    """Function that can be used as copytree() ignore parameter.

    Patterns is a sequence of glob-style patterns
    that are used to exclude files"""
    def _ignore_patterns(path, names):
        ignored_names = []
        for pattern in patterns:
            ignored_names.extend(fnmatch.filter(names, pattern))
        return set(ignored_names)
    return _ignore_patterns

您可以看到它返回一个接受路径和名称列表的函数,并且返回一组要忽略的名称。为了支持您的用例,请创建您自己的类似函数,该函数使用 path 参数。将您的函数传递给调用 copytree() 中的忽略参数。

或者,不要按原样使用 shutil。源代码短小精悍,因此剪切、粘贴和自定义并不难。


3
投票

您需要创建自己的忽略函数,该函数检查正在处理的当前目录,并仅当目录为“/Full/Path/To/aDir”时返回包含“Common”的列表。

def ignore_full_path_common(dir, files):
    if dir == '/Full/Path/To/aDir':
        return ['Common']
    return []

shutil.copytree(directory, target_dir, ignore=ignore_full_path_common)

2
投票

非常感谢您的回答。它帮助我设计了自己的

ignore_patterns()
函数来满足一些不同的需求。将代码粘贴到此处,可能会对某人有所帮助。

下面是

ignore_patterns()
函数,用于使用绝对路径排除多个文件/目录。

myExclusionList
--> 包含复制时要排除的文件/目录的列表。该列表可以包含通配符模式。列表中的路径是相对于提供的
srcpath
的。例如:

[排除清单]

java/app/src/main/webapp/WEB-INF/lib/test
unittests
python-buildreqs/apps/abc.tar.gz
3rd-party/jdk*

代码粘贴在下面

def copydir(srcpath, dstpath, myExclusionList, log):

    patternlist = []
    try:
        # Forming the absolute path of files/directories to be excluded
        for pattern in myExclusionList:
            tmpsrcpath = join(srcpath, pattern)
            patternlist.extend(glob.glob(tmpsrcpath)) # myExclusionList can contain wildcard pattern hence glob is used
        copytree(srcpath, dstpath, ignore=ignore_patterns_override(*patternlist))
    except (IOError, os.error) as why:
        log.warning("Unable to copy %s to %s because %s", srcpath, dstpath, str(why))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
    except Error as err:
        log.warning("Unable to copy %s to %s because %s", srcpath, dstpath, str(err))


# [START: Ignore Patterns]
# Modified Function to ignore patterns while copying.
# Default Python Implementation does not exclude absolute path
# given for files/directories

def ignore_patterns_override(*patterns):
    """Function that can be used as copytree() ignore parameter.
    Patterns is a sequence of glob-style patterns
    that are used to exclude files/directories"""
    def _ignore_patterns(path, names):
        ignored_names = []
        for f in names:
            for pattern in patterns:
                if os.path.abspath(join(path, f)) == pattern:
                    ignored_names.append(f)
        return set(ignored_names)
    return _ignore_patterns

# [END: Ignore Patterns]

0
投票

平台无关。路径全局模式 [".gitkeep","app/build","*.txt"]

    def callbackIgnore(paths):
        """ callback for shutil.copytree """
        def ignoref(directory, contents):
            arr = [] 
            for f in contents:
                for p in paths:
                    if (pathlib.PurePath(directory, f).match(p)):
                        arr.append(f)
            return arr
    
        return ignoref
© www.soinside.com 2019 - 2024. All rights reserved.