2011-09-14 923 views
51

我有一個目錄,'Dst目錄',其中有文件和文件夾,我有'src目錄',其中也有文件和文件夾。我想要做的是將'src Directory'的內容移動到'Dst Directory'並覆蓋存在的同名文件。因此,例如'Src Directory \ file.txt'需要移動到'Dst Directory \'並覆蓋現有的file.txt。這同樣適用於某些文件夾,移動文件夾和合並內容與'dst目錄'中的相同文件夾Python - 移動和覆蓋文件和文件夾

我目前使用shutil.move將src的內容移動到dst,但它不會這樣做如果文件已經存在,並且不會合並文件夾;它只會將文件夾放在現有的文件夾中。

更新:使事情變得更清晰;我正在做的是將檔案解壓縮到Dst目錄,然後將Src目錄的內容移到那裏並重新壓縮,從而有效地更新zip檔案中的文件。這將重複添加新文件或新版本的文件等,這就是爲什麼它需要覆蓋和合並

解決:我通過使用distutils.dir_util.copy_tree(src,dst)解決了我的問題,這複製文件夾和從src目錄到dst目錄的文件,並在必要時覆蓋/合併。希望能幫助一些人!

希望有道理, 謝謝!

+0

注意['distutils.dir_util.copy_tree'](https://docs.python.org/dev /distutils/apiref.html#distutils.dir_util.copy_tree)無法複製特殊文件,例如[命名管道](https://en.wikipedia.org/wiki/Named_pipe)(拋出'distutils.errors.DistutilsFileError')。 –

回答

35

改爲使用copy(),它願意覆蓋目標文件。如果你想讓第一棵樹消失,只需要將它分開即可。

http://docs.python.org/library/shutil.html#shutil.copy

http://docs.python.org/library/shutil.html#shutil.rmtree

更新:

做一個os.walk()在源代碼樹。對於每個目錄,檢查它是否存在於目的地端,如果它缺失,則檢查它是否爲os.makedirs()。對於每個文件,只需shutil.copy()和該文件將被創建或覆蓋,無論哪個適當。

+0

copy()can'儘管複製文件夾,可以嗎? – Artharos

+0

不,但每個文件上的'move()'也不會創建目標目錄,所以我認爲你的代碼已經在不存在的目標文件夾上做了一個'os.makedirs()'。啊!我想我現在明白了 - 你一次在*整個樹上做'move()'? Gotchya。將更新我的答案。 –

+0

感謝您的更新,與此相關的問題是,要複製的文件總是在變化(添加新文件等),所以如果您明白這一點,每次添加新文件以便移動時都必須更新代碼。無論如何,我用distutils.dir_util.copy_tree(src,dst)來管理它,它複製文件夾和文件,並在必要時覆蓋/合併,感謝幫助 – Artharos

1

看一看:os.remove刪除現有文件。

+0

問題在於我想添加到文件夾中的文件將發生變化(新的文件將被添加並更新舊的文件),所以我不能擁有要刪除的內容的集合列表,謝謝 – Artharos

44

這將通過源目錄,創建不已經在目標目錄中存在的任何目錄,並從源移動文件到目標目錄:

import os 
import shutil 

root_src_dir = 'Src Directory\\' 
root_dst_dir = 'Dst Directory\\' 

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.move(src_file, dst_dir) 

任何預先存在的文件將被首先刪除(通過os.remove),然後被相應的源文件替換。目標中已存在但未存在於源中的任何文件或目錄將保持不變。

+3

這很好,謝謝你!我認爲這就是布蘭登克雷格羅德斯所談論的,但是謝謝你提供了一個片段!不幸的是,你不能有兩個正確的答案^^ – Artharos

+1

沒有問題。 :)希望我們的每個答案都有幫助。 –

+2

複製它們就像用「shutil.copy」替換「shutil.move」一樣簡單。 – Karoh

6

由於以上都不適合我,所以我寫了自己的遞歸函數。調用函數copyTree(dir1,dir2)來合併目錄。在多平臺Linux和Windows上運行。

def forceMergeFlatDir(srcDir, dstDir): 
    if not os.path.exists(dstDir): 
     os.makedirs(dstDir) 
    for item in os.listdir(srcDir): 
     srcFile = os.path.join(srcDir, item) 
     dstFile = os.path.join(dstDir, item) 
     forceCopyFile(srcFile, dstFile) 

def forceCopyFile (sfile, dfile): 
    if os.path.isfile(sfile): 
     shutil.copy2(sfile, dfile) 

def isAFlatDir(sDir): 
    for item in os.listdir(sDir): 
     sItem = os.path.join(sDir, item) 
     if os.path.isdir(sItem): 
      return False 
    return True 


def copyTree(src, dst): 
    for item in os.listdir(src): 
     s = os.path.join(src, item) 
     d = os.path.join(dst, item) 
     if os.path.isfile(s): 
      if not os.path.exists(dst): 
       os.makedirs(dst) 
      forceCopyFile(s,d) 
     if os.path.isdir(s): 
      isRecursive = not isAFlatDir(s) 
      if isRecursive: 
       copyTree(s, d) 
      else: 
       forceMergeFlatDir(s, d) 
+0

這是唯一一個有效的工作 – user1447414

+0

在使用其他答案時,什麼情況不適合你? – cgmb

+0

值得注意的是,如果src與dst中的目錄具有相同名稱的文件,則此解決方案會將該文件放入共享其名稱的目錄中,而[Ray Vega的解決方案](http://stackoverflow.com/a/ 7420617/331041)會拋出'OSError:[Errno 21]是一個目錄。 – cgmb

0

我有類似的問題。我想移動文件和文件夾結構並覆蓋現有文件,但不刪除目標文件夾結構中的任何內容。

我解決了它通過使用os.walk()遞歸調用我的功能和使用shutil.move()我想覆蓋的文件和文件夾不存在。

它的工作方式與shutil.move()類似,但有利於現有文件只被覆蓋,但不會被刪除。

import os 
import shutil 

def moverecursively(source_folder, destination_folder): 
    basename = os.path.basename(source_folder) 
    dest_dir = os.path.join(destination_folder, basename) 
    if not os.path.exists(dest_dir): 
     shutil.move(source_folder, destination_folder) 
    else: 
     dst_path = os.path.join(destination_folder, basename) 
     for root, dirs, files in os.walk(source_folder): 
      for item in files: 
       src_path = os.path.join(root, item) 
       if os.path.exists(dst_file): 
        os.remove(dst_file) 
       shutil.move(src_path, dst_path) 
      for item in dirs: 
       src_path = os.path.join(root, item) 
       moverecursively(src_path, dst_path) 
3

如果您還需要重寫與只讀標誌使用的文件這樣的:

def copyDirTree(root_src_dir,root_dst_dir): 
""" 
Copy directory tree. Overwrites also read only files. 
:param root_src_dir: source directory 
:param root_dst_dir: destination directory 
""" 
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): 
      try: 
       os.remove(dst_file) 
      except PermissionError as exc: 
       os.chmod(dst_file, stat.S_IWUSR) 
       os.remove(dst_file) 

     shutil.copy(src_file, dst_dir)