【问题标题】:Filter directory when using shutil.copytree?使用 shutil.copytree 时过滤目录?
【发布时间】:2011-10-20 20:47:41
【问题描述】:

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

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


    【解决方案1】:

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

    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_patterns() 可用于创建 这样的可调用对象会忽略基于 glob 样式模式的名称。

    【讨论】:

    • 小修正,ignoref函数应该返回列表(即[f for f in ...]而不是生成器。
    【解决方案2】:

    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)
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-28
          • 2016-01-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          • 2015-11-24
          • 1970-01-01
          相关资源
          最近更新 更多