在一个目录中运行以下代码,该目录包含一个名为bar的目录(包含一个或多个文件)和一个名为baz的目录(也包含一个或多个文件)。确保没有名为foo的目录。
import shutil
shutil.copytree('bar', 'foo')
shutil.copytree('baz', 'foo')
它将失败:
$ python copytree_test.py
Traceback (most recent call last):
File "copytree_test.py", line 5, in <module>
shutil.copytree('baz', 'foo')
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/shutil.py", line 110, in copytree
File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/os.py", line 172, in makedirs
OSError: [Errno 17] File exists: 'foo'
我想让它像我输入的那样工作:
$ mkdir foo
$ cp bar/* foo/
$ cp baz/* foo/
我需要使用shutil.copy()复制每个文件在baz到foo?(在我已经用shutil.copytree()将'bar'的内容复制到'foo'后?)或者有更简单/更好的方法吗?
我无法编辑上面的“Boris Dalstein”答案,所以这里是这段代码的改进版本:
编辑所做的改进:
输入参数可以是str path或pathlib。路径对象。输入提示会有帮助。
如果源是一个目录,它也会创建该目录
类型是为局部变量定义的,因此IDE不会发出警告
# Recusively copies the content of the directory src to the directory dst.
# If dst doesn't exist, it is created, together with all missing parent directories.
# If a file from src already exists in dst, the file in dst is overwritten.
# Files already existing in dst which don't exist in src are preserved.
# Symlinks inside src are copied as symlinks, they are not resolved before copying.
#
def copy_dir(source: Union[str, pathlib.Path], destination: Union[str, pathlib.Path]):
destination_path: pathlib.Path
if isinstance(source, str):
source_path = pathlib.Path(source)
elif isinstance(source, pathlib.Path):
source_path = source
if isinstance(destination, str):
destination_path = pathlib.Path(destination)
elif isinstance(destination, pathlib.Path):
destination_path = destination
destination_path.mkdir(parents=True, exist_ok=True)
if source_path.is_dir():
destination_path = destination_path.joinpath(source_path.name)
destination_path.mkdir(parents=True, exist_ok=True)
for item in os.listdir(source_path):
s: pathlib.Path = source_path / item
d: pathlib.Path = destination_path / item
if s.is_dir():
copy_dir(s, d)
else:
shutil.copy2(str(s), str(d))
在atzz对函数的回答略有改进,上面的函数总是尝试将文件从源复制到目标。
def copytree(src, dst, symlinks=False, ignore=None):
if not os.path.exists(dst):
os.makedirs(dst)
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dst, item)
if os.path.isdir(s):
copytree(s, d, symlinks, ignore)
else:
if not os.path.exists(d) or os.stat(s).st_mtime - os.stat(d).st_mtime > 1:
shutil.copy2(s, d)
在我上面的实现中
如果不存在,则创建输出目录
通过递归调用我自己的方法来复制目录。
当我们实际复制文件时,我检查文件是否被修改了
我们应该效仿。
我使用上面的函数以及scons构建。它帮助了我很多,因为每次当我编译时,我可能不需要复制整个文件集。但仅限于修改过的文件。
这是受到atzz提供的原始最佳答案的启发,我只是添加了替换文件/文件夹逻辑。所以它实际上并没有合并,而是删除现有的文件/文件夹并复制新的文件/文件夹:
import shutil
import os
def copytree(src, dst, symlinks=False, ignore=None):
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dst, item)
if os.path.exists(d):
try:
shutil.rmtree(d)
except Exception as e:
print e
os.unlink(d)
if os.path.isdir(s):
shutil.copytree(s, d, symlinks, ignore)
else:
shutil.copy2(s, d)
#shutil.rmtree(src)
取消注释rmtree,使其成为一个move函数。