为什么这个递归复制功能会将所有文件复制到正确的每个目录之上?

时间:2012-04-11 16:50:23

标签: python recursion os.walk

我编写了一个函数,用于将文件从目录A复制到目录B递归。 代码是这样的:

import os
import shutil
import sys
from os.path import join, exists

def copy_file(src, dest):
    for path, dirs, files in os.walk(src, topdown=True):
        if len(dirs) > 0:
            for di in dirs:
                copy_file(join(path, di), join(dest,  di))

        if not exists(dest):
            os.makedirs(dest)
        for fi in files:
            shutil.copy(join(path, fi), dest)

在我的测试中,输入参数是这样的:

src = d:/dev

它有一个名为py的子目录。此外,py有一个名为test

的子目录
dest = d:/dev_bak

所以,当我测试我的代码时,发生了一些奇怪的事情。 在我的dest目录d:/dev_bak中,创建了三个子目录。 那就是:d:/dev_bak/py; d:/dev_bak/py/test; d:/dev_bak/test

在我的设计中,dev_bak的结构与dev相同。那么,为什么会这样呢!

2 个答案:

答案 0 :(得分:2)

您可以通过

轻松诊断出来
    print path, dirs, files

正下方

for path, dirs, files in os.walk(src, topdown=True):

基本上,你要两次递归。

本身,os.walk下降到子目录中。你通过递归调用自己的函数来双下降。以下是print语句的一些示例输出:

>>> copy_file("c:\Intel", "c:\Intel-Bak")
c:\Intel ['ExtremeGraphics', 'Logs'] []
c:\Intel\ExtremeGraphics ['CUI'] []
c:\Intel\ExtremeGraphics\CUI ['Resource'] []
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI ['Resource'] []
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\Logs [] ['IntelChipset.log', 'IntelControlCenter.log', 'IntelGFX.log', 'IntelGFXCoin.log']
c:\Intel\ExtremeGraphics ['CUI'] []
c:\Intel\ExtremeGraphics\CUI ['Resource'] []
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI ['Resource'] []
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\ExtremeGraphics\CUI\Resource [] ['Intel\xae Graphics and Media Control Panel.lnk', 'Intel\xae HD Graphics.lnk']
c:\Intel\Logs [] ['IntelChipset.log', 'IntelControlCenter.log', 'IntelGFX.log', 'IntelGFXCoin.log']

如您所见,目录被访问了两次。

你应该修改程序的逻辑,这样它只访问每个目录一次,但理论上你可以忽略你去过的任何目录:

visited = []
def copy_file(src, dest):
    for path, dirs, files in os.walk(src, topdown=True):
        if path not in visited:
            for di in dirs:
                print dest, di
                copy_file(join(path, di), join(dest,  di))
            if not exists(dest):
                os.makedirs(dest)
            for fi in files:
                shutil.copy(join(path, fi), dest)
            visited.append(path)

答案 1 :(得分:0)

shutil模块已经有一个copytree函数,它将递归复制目录。您可能希望使用它而不是提供自己的实现。