使用shutil.copytree时过滤目录?

时间:2011-10-20 20:47:42

标签: python shutil copytree

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

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的目录都将在“树”中过滤,这不是我想要的。

有什么建议吗?

感谢。

4 个答案:

答案 0 :(得分:13)

您可以创建自己的忽略功能:

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.abspath(os.path.join(directory, f)) == path)
  return ignoref

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

来自文档:

  

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

答案 1 :(得分: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()的调用中的ignore参数。

或者,不要按原样使用 shutil 。源代码简短而且甜美,因此不难切割,粘贴和自定义。

答案 2 :(得分:3)

您需要创建自己的ignore函数,该函数检查当前正在处理的目录,并且仅当dir为'/ 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)

答案 3 :(得分:0)

非常感谢您的回答。它帮助我设计了我自己的 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]