在Python中使用特殊的大小写处理实现递归复制
我想在Python中实现一个版本的在Python中使用特殊的大小写处理实现递归复制,python,unix,filesystems,shutil,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的目录。我
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
,该文件可能包含经过处理的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\u dir1
的正确对应位置?我希望copy_dir1
(目标目录)的结构与dir1
(源目录)完全相同,只是对包含.bar
文件的目录进行了特殊处理。听起来您希望使用忽略参数:
如果给出了ignore,则它必须是一个可调用的函数,它将接收由copytree()
访问的目录作为其参数,以及由os.listdir()
返回的目录内容列表。由于copytree()
是递归调用的,因此将为复制的每个目录调用一次ignore callable。可调用项必须返回相对于当前目录的目录名和文件名序列(即第二个参数中的项目子集);这些名称将在复制过程中被忽略。”ignore_patterns()'可用于创建忽略基于全局样式模式的名称的可调用对象
因此,类似这样的方法应该有效:
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)
编辑展开的问题和示例
这里有一个例子。简化的ignore函数仍然会创建一个空的特殊目录,但是在进行特殊的zip复制之前,很容易删除它。我还嵌套了这个特殊函数,因此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')
输出
Found special dirs: ['dir1\\specialdir']
Zip "dir1\specialdir" to "dira\specialdir.zip"
Found special dirs: ['dir1\\specialdir']
Zip "dir1\specialdir" to "dirb\specialdir.zip"
听起来很有用,但我的用例有点不同,我最初没有解释清楚。我不想跳过这组文件,但可能会对它们进行后处理,并将后处理版本复制到
outdir
。在这种情况下,我应该只使用walk
?ignore函数可以做任何事情,包括收集文件名以进行后期处理。例如,如果函数返回一个空列表,它不会忽略任何内容,只会变成每个目录的回调。但是是否可以让回调在目标目录中插入一个文件(这是对输入目录中的文件进行某些后处理的结果),然后返回空的?否,没有办法指定要复制的额外文件,只有要忽略的原始目录中的文件,这就是您的问题所在。您可以在列表中收集特殊文件,然后对其进行后期处理并将其复制到目标目录,甚至可以在回调过程中自行处理并复制这些文件,并将已处理的文件作为忽略列表返回。谢谢我编辑了我的回答,以反映我编写您的建议的尝试