【问题标题】:How to perform a non recursive copy using python如何使用python执行非递归复制
【发布时间】:2019-02-04 02:06:30
【问题描述】:

我需要复制具有特定模式的文件。我需要使用shutil 在给定目录上执行非递归复制。我尝试使用下面给出的代码执行递归复制。是否可以在其中指定任何选项来执行非递归复制。

    from fnmatch import fnmatch, filter
    from os.path import isdir, join
    from shutil import copytree, ignore_patterns

    src_directory = r'PATH'
    dst_directory = r'PATH'
    copytree(src_directory, ignored_directory,ignore=ignore_patterns('*.txt'))

【问题讨论】:

  • 非递归是什么意思?只有目录中的文件或文件和目录中的文件,但这些目录下没有?
  • 只有目录中的文件而不是文件夹@ThatBird
  • 任何通过通配符复制文件的解决方案都忽略了 copytree 的许多不错的功能,例如符号链接处理、复制文件元数据等。This solution 创建了一个真正的非递归版本的 copytree

标签: python copy shutil non-recursive


【解决方案1】:

由于您选择使用shutil 中的copytree,请注意,循环文件以复制每个文件的任何解决方案都会遗漏copytree 的许多不错的功能,例如符号链接处理、复制文件元数据等

您可以通过创建一个名为copyfiles 的非递归copytree 来保留所有附加功能。 copyfilescopytree 的工作方式相同,只是它扩展了ignore 参数,以便在复制时也忽略文件夹。

import shutil, os

def copyfiles(src, dst, ignore=lambda a, b: set(), **kwargs):
    return shutil.copytree(src, dst, ignore=lambda s, names: set(ignore(s, names)).union(set(filter(lambda name: os.path.isdir(os.path.join(s, name)), names))), **kwargs)
# use copyfiles like so:

copyfiles(src_directory, dst_directory, ignore=shutil.ignore_patterns('*.txt')) # copies non-recursively

【讨论】:

    【解决方案2】:

    首先确保目标目录存在。 然后使用glob.glob 创建要忽略的所有文件的列表。然后遍历src目录下的所有文件和目录,如果是文件且不在ignore列表中,则将每个文件复制到dst目录下:

    import os, shutil, glob
    src = 'my_dir'
    dst = 'my_dir_cp'
    
    try:
        os.mkdir(dst)
    except FileExistsError:
        pass
    
    ignore = glob.glob(os.path.join(src, '*.txt'))
    for file in os.listdir(src):
        file = os.path.join(src, file)
        if file not in ignore and os.path.isfile(file):
            shutil.copy(file, dst)
    

    一个完整的例子:

    $ ls my_dir
    bob  cat.txt  fish  jim
    $ python -q
    >>> import os, shutil, glob
    >>> src = 'my_dir'
    >>> dst = 'my_dir_cp'
    >>> 
    >>> try:
    ...     os.mkdir(dst)
    ... except FileExistsError:
    ...     pass
    ... 
    >>> ignore = glob.glob(os.path.join(src, '*.txt'))
    >>> for file in os.listdir(src):
    ...     file = os.path.join(src, file)
    ...     if file not in ignore and os.path.isfile(file):
    ...         shutil.copy(file, dst)
    ... 
    'my_dir_cp/jim'
    'my_dir_cp/bob'
    >>> 
    $ ls my_dir_cp
    bob  jim
    

    如果您希望能够忽略多个glob 模式,那么您可以glob.glob 每个模式并将结果连接在一起(在列表理解中):

    import os, shutil, glob
    src = 'my_dir'
    dst = 'my_dir_cp'
    
    try:
        os.mkdir(dst)
    except FileExistsError:
        pass
    
    patterns_to_ignore = ['*.txt', '*.bat']
    ignore = [e for p in patterns_to_ignore for e in glob.glob(os.path.join(src, p))]
    for file in os.listdir(src):
        file = os.path.join(src, file)
        if file not in ignore and os.path.isfile(file):
            shutil.copy(file, dst)
    

    【讨论】:

    • 如何添加多个带有忽略的扩展名,例如 *.bat、*txt 等 @Joe Iddon
    • @Jarvis 好的,我会补充,但请接受这个答案!
    【解决方案3】:

    这更像是一种 hack,但会以非递归方式将目录中的所有文件复制到目标目录。您可以使用 glob 或正则表达式来忽略文件 -

    import re
    
    def copytree(src, dst):
         for item in [f for f in os.listdir(src) if os.path.isfile(os.path.join(src, f)) if not re.match(f, '[.]txt$')]:
             s = os.path.join(src, item)
             d = os.path.join(dst, item)
             shutil.copy2(s, d)
    

    【讨论】:

      猜你喜欢
      • 2015-10-30
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2023-03-26
      • 2010-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多