2012-04-11 31 views
0

我寫了一個函數將文件從目錄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) 

在我的測試中,輸入ARG遊戲是這樣的:

 
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

您可以輕鬆地在

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) 
+0

謝謝。但我有另一個問題。當我讀到os.walk()的文檔時,他們說:「當topdown爲True時,調用者可以就地修改dirnames列表(可能使用del或slice賦值),而walk()只會遞歸到子目錄中名字保留在dirnames中;「 – linuxlsx 2012-04-12 02:06:11

+0

@linuxlsx對。通過遍歷'dirs'並刪除其中的每個目錄,您將其保留爲空。所以'os.walk'根本不會下降 - 唯一的訪問是通過遞歸調用完成的。你已經把'os.walk'變成了一個奇特的'os.listdir'。我不確定你的意思是「爲什麼它工作」。 – agf 2012-04-12 02:37:28

0

shutil模塊已經有一個copytree函數,它將遞歸複製目錄。您可能想使用它而不是提供自己的實現。

+0

這是最有可能的一類或自-教育。 – agf 2012-04-11 16:55:42

+0

沒錯,copytree()做得很好,但是我的問題有些不同。 copytree請求目標目錄不能存在,在我的設計中,目標目錄可能已經存在。 – linuxlsx 2012-04-12 01:52:17

相關問題