在Python中递归复制文件或目录

在Python中递归复制文件或目录,python,Python,Python似乎有复制文件的函数(例如shutil.copy)和复制目录的函数(例如shutil.copytree),但我还没有找到任何同时处理这两个问题的函数。当然,检查是否要复制文件或目录很简单,但这似乎是一个奇怪的遗漏 是否真的没有像unixcp-r命令那样工作的标准函数,即支持目录和文件以及递归复制?在Python中解决这个问题最优雅的方法是什么?Unixcp不“同时支持目录和文件”: betelgeuse:tmp james$ cp source/ dest/ cp: source/

Python似乎有复制文件的函数(例如
shutil.copy
)和复制目录的函数(例如
shutil.copytree
),但我还没有找到任何同时处理这两个问题的函数。当然,检查是否要复制文件或目录很简单,但这似乎是一个奇怪的遗漏


是否真的没有像unix
cp-r
命令那样工作的标准函数,即支持目录和文件以及递归复制?在Python中解决这个问题最优雅的方法是什么?

Unix
cp
不“同时支持目录和文件”:

betelgeuse:tmp james$ cp source/ dest/
cp: source/ is a directory (not copied).
要使cp复制一个目录,您必须使用“-r”标志手动告诉cp它是一个目录

当传递一个文件名时-
cp-r
会有一些中断,因为源代码很乐意只复制一个文件;copytree不会。我建议您首先调用,如果引发异常,请使用重试


python shutil.copytree方法一团糟。我已经做了一个正确的工作:

def copydirectorykut(src, dst):
    os.chdir(dst)
    list=os.listdir(src)
    nom= src+'.txt'
    fitx= open(nom, 'w')

    for item in list:
        fitx.write("%s\n" % item)
    fitx.close()

    f = open(nom,'r')
    for line in f.readlines():
        if "." in line:
            shutil.copy(src+'/'+line[:-1],dst+'/'+line[:-1])
        else:
            if not os.path.exists(dst+'/'+line[:-1]):
                os.makedirs(dst+'/'+line[:-1])
                copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
            copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
    f.close()
    os.remove(nom)
    os.chdir('..')

shutil.copy
shutil.copy2
正在复制文件

shutil.copytree
复制包含所有文件和所有子文件夹的文件夹
shutil.copytree
正在使用
shutil.copy2
复制文件

因此,与您所说的
cp-r
类似的是
shutil.copytree
,因为
cp-r
以文件夹及其文件/子文件夹为目标并进行复制,如
shutil.copytree
。如果不使用
-r
cp
复制文件,如
shutil.copy
shutil.copy2
do。

要添加和回答,这里有一种递归复制文件和文件夹的替代方法。(Python 3.X)


如果这是你第一次,但你不知道如何递归复制文件和文件夹,我希望这会有所帮助。

包括copytree()的代码,该代码演示如何处理普通文件、符号链接和目录。这个答案没有解决这个问题。这应该是评论,而不是回答。是的,这是一团糟。Python试图反映底层系统调用,从而使可视界面变得更糟糕。虽然在复制文件和复制树之间切换并不困难,但这并不是必须的。也许可以在Python bug跟踪器上提交一个增强请求,以允许
copytree
复制单个文件?我认为复制树就是您想要的。我认为使用os.path.isdir(src)简单地检查src是否是一个目录,而不是捕获这样的异常会更干净。或者有什么特别的原因应该在这里使用异常吗?1)因为在Python世界中,EAFP(请求原谅比允许更容易)比LBYL(三思而后行)更受欢迎。我可以为您提供有关这方面的链接,如果这对您来说是新的。2) 库函数已经间接地检查了这一点,那么为什么要复制检查呢?3) 没有任何东西可以阻止
shutil.copytree
函数在将来改进和管理这两种情况。4) 在Python中,异常并不是那么例外;e、 迭代通过抛出StopIteration异常来停止。在这种情况下,处理异常需要6行,而检查类型需要4行。虽然不多,但最终还是加起来了。另外,正如您所说,copytree将来也可能很好地支持文件。但不可能知道该实现会是什么样子。也许它会在复制有效的情况下抛出异常?在这种情况下,我的代码会因为添加的功能而突然停止工作。但你可能是对的,异常在Python中非常常见,我觉得这很烦人,但这可能是因为我似乎从未习惯于它。实际上,在这种情况下,异常有一个明显的客观优势:它是完全可能的(尽管可能性很小)在我个人看来,在except中添加核心功能是一种不好的做法,不管您使用哪种语言。它将功能放在了一个很多开发人员都不会搜索的地方。此外,如果您不编写注释,经验较少的python开发人员将无法真正理解此重试的目的。如果您需要为像这里这样的小事添加注释,那么您的代码样式中的某些内容是错误的。最后,编写if/else会使代码更易于阅读。该代码适用于单个文件检查(检查覆盖问题),但不适用于二进制文件,如“zip”。为什么不使用简单的python文件拷贝而不是逐行读/写呢?我认为您不理解这个问题。尝试
shutil.copytree('C:\myfile.txt','C:\otherfile')
。它不起作用。这就是OP要问的。。。7年前,当然不行了。就像cp不处理文件夹一样。你需要一个特别的选择。copy和copytree是处理复制的最佳方式。如果copytree可以将目标和文件放在一起,那么很容易出错。您必须知道Linux和Python的目标是什么。那很难。另外还有人在这里发表了评论,但看到问题和回复,忍不住要回答。优雅的方法是知道你想要做什么,而不是没有任何控制的通用副本。
def copydirectorykut(src, dst):
    os.chdir(dst)
    list=os.listdir(src)
    nom= src+'.txt'
    fitx= open(nom, 'w')

    for item in list:
        fitx.write("%s\n" % item)
    fitx.close()

    f = open(nom,'r')
    for line in f.readlines():
        if "." in line:
            shutil.copy(src+'/'+line[:-1],dst+'/'+line[:-1])
        else:
            if not os.path.exists(dst+'/'+line[:-1]):
                os.makedirs(dst+'/'+line[:-1])
                copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
            copydirectorykut(src+'/'+line[:-1],dst+'/'+line[:-1])
    f.close()
    os.remove(nom)
    os.chdir('..')
import os, shutil

root_src_dir = r'C:\MyMusic'    #Path/Location of the source directory
root_dst_dir = 'D:MusicBackUp'  #Path to the destination folder

for src_dir, dirs, files in os.walk(root_src_dir):
    dst_dir = src_dir.replace(root_src_dir, root_dst_dir, 1)
    if not os.path.exists(dst_dir):
        os.makedirs(dst_dir)
    for file_ in files:
        src_file = os.path.join(src_dir, file_)
        dst_file = os.path.join(dst_dir, file_)
        if os.path.exists(dst_file):
            os.remove(dst_file)
        shutil.copy(src_file, dst_dir)