使用特殊案例处理在Python中实现递归副本

时间:2013-02-03 00:35:06

标签: python unix filesystems shutil

我想在Python中实现cp -r版本,以特殊方式处理某些目录。如果您执行mycp.py -r indir outdir,我希望indir及其所有文件/子目录完全复制到outdir,但某些文件名除外。在Python中最便携的方法是什么?

示例:我有这个目录结构:

dir1/
  file1
  dir2/
    dir3/
  specialdir/
    myfile.bar

file1是一个文件,specialdir是一个包含文件myfile.bar的目录。我想复制dir1及其所有内容,但特别处理其中包含*.bar个文件的目录。在这种情况下,只有specialdir符合条件。我希望mycopy复制所有dir1,但用自己的压缩版本替换任何特殊目录。在上面的示例中,这意味着按原样复制dir1,但将specialdir替换为可能包含处理版specialdir.zip的{​​{1}}。

我试图按照下面的建议,但我不知道如何处理复制:

myfile.bar

如果我尝试它,它会正确检测特殊目录:

import os
import shutil

SPECIAL_DIRS = []

def is_special_dir(path, dirnames):
    """directories are special if they have .bar files"""
    special_dirs = []
    for d in dirnames:
        d = os.path.join(path, d)
        if os.path.isdir(d):
            files_in_d = os.listdir(d)
            for f in files_in_d:
                if f.endswith(".bar"):
                    # directory is special if it contains
                    # .bar files
                    special_dirs.append(d)
    SPECIAL_DIRS.extend(special_dirs)
    return special_dirs

def my_copy(indir, outdir):
    shutil.copytree(indir, outdir, ignore=is_special_dir)
    print "Found special dirs: ", SPECIAL_DIRS

# make a copy of dir1 but handle special directories
# differently
my_copy("dir1", "copy_dir1")

如何在$ copy_test.py Found special dirs: ['dir1/dir2/specialdir'] 的相应位置插入specialdir?我希望copy_dir1(目标目录)具有与copy_dir1(源目录)完全相同的结构,除非对包含dir1文件的目录进行特殊处理。

1 个答案:

答案 0 :(得分:3)

听起来您希望shutil.copytree使用 ignore 参数:

  

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

所以这样的事情应该有效:

copytree()

编辑扩展问题和示例

这是一个例子。简化的忽略函数仍然会创建一个空的特殊目录,但在执行特殊的zip拷贝之前很容易删除。我还嵌套了特殊函数,因此可以多次使用def what_to_ignore(path,names): if is_special(path): # process names here returning any or all to ignore shutil.copytree(indir,outdir,ignore=what_to_ignore) 而不依赖于使用全局变量。拉链是用户的练习:

my_copy

<强>输出

import fnmatch
import shutil
import os

def my_copy(indir, outdir):

    special = []

    def is_special_dir(path, names):
        """directories are special if they have .bar files"""
        if fnmatch.filter(names,'*.bar'):
            special.append(path)
            return names
        return []    

    shutil.copytree(indir, outdir, ignore=is_special_dir)
    print('Found special dirs:',special)

    for src in special:
        rel = os.path.relpath(src,indir)
        dst = os.path.join(outdir,rel)
        os.rmdir(dst)
        print('Zip "{}" to "{}.zip"'.format(src,dst))

my_copy('dir1','dira')
my_copy('dir1','dirb')