如何在python中递归复制目录并覆盖所有?

时间:2012-10-02 02:37:58

标签: python copy distutils

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

看起来就像distutils.dir_util.copy_tree可能是工作的正确工具,但不确定是否有更容易/更明显的用于这样一个简单的任务。

如果它是正确的工具,我该如何使用它?根据{{​​3}},它有8个参数。我必须通过所有8个只是srcdstupdate,如果是,我是如何(我是Python的新手)。

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

5 个答案:

答案 0 :(得分:52)

您可以使用distutils.dir_util.copy_tree。它工作正常,您不必传递每个参数,只有srcdst是强制性的。

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

如果您想使用问题评论中建议的cp工具,请注意使用subprocess模块目前是产生新流程的推荐方法,如{{3}中所示}。

答案 1 :(得分:30)

查看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)

如果dirs已经存在,Vincent对于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

答案 2 :(得分:20)

这是一个简单的解决方案,用源递归覆盖目标,随时创建任何必要的目录。这不会处理符号链接,但它只是一个简单的扩展(请参阅@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)

答案 3 :(得分:7)

在Python 3.8中,dirs_exist_ok关键字参数was addedshutil.copytree()

dirs_exist_ok决定是否在dst或任何丢失的父目录已经存在的情况下引发异常。

因此,即使目标目录已存在,以下内容也可以在最新版本的Python中运行:

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

一个主要好处是它比distutils.dir_util.copy_tree()更具灵活性,因为它需要忽略文件上的其他参数,等等。还有一个PEP草案(PEP 632associated discussion),建议distutils可能会被弃用,然后在将来的Python 3版本中删除。

答案 4 :(得分:0)

我的简单答案。

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)
相关问题