85

我正在尝试将/home/myUser/dir1/其所有内容(及其内容等)复制到/home/myuser/dir2/python 中。此外,我希望副本覆盖dir2/.

看起来可能是适合这项distutils.dir_util.copy_tree工作的工具,但不确定是否有任何更容易/更明显的方法可用于如此简单的任务。

如果它是正确的工具,我该如何使用它?根据文档,它需要 8 个参数。我是否必须通过所有 8 个只是src, dstand update,如果是,如何(我是 Python 的新手)。

如果那里有更好的东西,有人可以给我一个例子并指出我正确的方向吗?提前致谢!

4

5 回答 5

74

您可以使用distutils.dir_util.copy_tree. 它工作得很好,你不必传递每个参数,只有src并且dst是强制性的。

但是,在您的情况下,您不能使用类似的工具,shutil.copytree因为它的行为不同:由于目标目录不能存在,因此此功能不能用于覆盖其内容。

如果您想cp按照问题评论中的建议使用该工具,请注意使用该subprocess模块目前是生成新进程的推荐方式,如您在 os.system 函数的文档中所见

于 2012-10-02T08:04:54.483 回答
53

看看shutil包装,尤其是rmtreecopytree。您可以使用 . 检查文件/路径是否存在os.paths.exists(<path>)

import shutil
import os

def copy_and_overwrite(from_path, to_path):
    if os.path.exists(to_path):
        shutil.rmtree(to_path)
    shutil.copytree(from_path, to_path)

copytree如果目录已经存在,文森特关于不工作的说法是正确的。distutils更好的版本也是如此。下面是固定版本shutil.copytree。它基本上是 1-1 复制的,除了第一个os.makedirs()放在 if-else-construct 后面:

import os
from shutil import *
def copytree(src, dst, symlinks=False, ignore=None):
    names = os.listdir(src)
    if ignore is not None:
        ignored_names = ignore(src, names)
    else:
        ignored_names = set()

    if not os.path.isdir(dst): # This one line does the trick
        os.makedirs(dst)
    errors = []
    for name in names:
        if name in ignored_names:
            continue
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks, ignore)
            else:
                # Will raise a SpecialFileError for unsupported file types
                copy2(srcname, dstname)
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error, err:
            errors.extend(err.args[0])
        except EnvironmentError, why:
            errors.append((srcname, dstname, str(why)))
    try:
        copystat(src, dst)
    except OSError, why:
        if WindowsError is not None and isinstance(why, WindowsError):
            # Copying file access times may fail on Windows
            pass
        else:
            errors.extend((src, dst, str(why)))
    if errors:
        raise Error, errors
于 2012-10-02T09:02:48.397 回答
33

这是一个简单的解决方案,可以用源递归覆盖目标,同时创建任何必要的目录。这不处理符号链接,但它会是一个简单的扩展(见上面@Michael 的回答)。

def recursive_overwrite(src, dest, ignore=None):
    if os.path.isdir(src):
        if not os.path.isdir(dest):
            os.makedirs(dest)
        files = os.listdir(src)
        if ignore is not None:
            ignored = ignore(src, files)
        else:
            ignored = set()
        for f in files:
            if f not in ignored:
                recursive_overwrite(os.path.join(src, f), 
                                    os.path.join(dest, f), 
                                    ignore)
    else:
        shutil.copyfile(src, dest)
于 2013-04-05T00:54:32.720 回答
27

在 Python 3.8 中,dirs_exist_ok关键字参数被添加shutil.copytree()

dirs_exist_ok指示是否引发异常以防万一dst或任何缺少的父目录已经存在。

因此,即使目标目录已经存在,以下内容也适用于最新版本的 Python:

shutil.copytree(src, dest, dirs_exist_ok=True)  # 3.8+ only!

一个主要的好处是它比 更灵活distutils.dir_util.copy_tree(),因为它需要忽略文件的附加参数等(请参阅文档)。最重要的是,已接受的PEP 632还声明distutils将在 Python 3 的未来版本中弃用并随后将其删除。

于 2020-10-13T17:15:35.030 回答
1

我的简单回答。

def get_files_tree(src="src_path"):
    req_files = []
    for r, d, files in os.walk(src):
        for file in files:
            src_file = os.path.join(r, file)
            src_file = src_file.replace('\\', '/')
            if src_file.endswith('.db'):
                continue
            req_files.append(src_file)

    return req_files
def copy_tree_force(src_path="",dest_path=""):
    """
    make sure that all the paths has correct slash characters.
    """
    for cf in get_files_tree(src=src_path):
        df= cf.replace(src_path, dest_path)
        if not os.path.exists(os.path.dirname(df)):
            os.makedirs(os.path.dirname(df))
        shutil.copy2(cf, df)
于 2020-11-29T19:22:57.987 回答