Python似乎具有複製文件的功能(例如shutil.copy
)和用於複製目錄的功能(例如shutil.copytree
),但是我還沒有找到處理兩者的函數。當然,檢查你是否想要複製一個文件或一個目錄很簡單,但這看起來像是一個奇怪的遺漏。在Python中遞歸複製文件或目錄
是否真的沒有像unix cp -r
命令一樣工作的標準功能,即支持目錄和文件以及遞歸複製?在Python中解決這個問題的最優雅方式是什麼?
Python似乎具有複製文件的功能(例如shutil.copy
)和用於複製目錄的功能(例如shutil.copytree
),但是我還沒有找到處理兩者的函數。當然,檢查你是否想要複製一個文件或一個目錄很簡單,但這看起來像是一個奇怪的遺漏。在Python中遞歸複製文件或目錄
是否真的沒有像unix cp -r
命令一樣工作的標準功能,即支持目錄和文件以及遞歸複製?在Python中解決這個問題的最優雅方式是什麼?
我建議你先打電話shutil.copytree
,如果拋出異常,則用shutil.copy
重試。
import shutil, errno
def copyanything(src, dst):
try:
shutil.copytree(src, dst)
except OSError as exc: # python >2.5
if exc.errno == errno.ENOTDIR:
shutil.copy(src, dst)
else: raise
我認爲簡單地檢查src是否是使用os.path.isdir(src)的目錄而不是像這樣捕獲異常會更簡潔。或者有什麼特別的理由應該在這裏使用異常呢? – pafcu 2010-01-03 13:09:44
1)因爲在Python世界中EAFP(比請求寬鬆要求寬鬆)比LBYL更優先(在你跳躍之前)。如果聽起來對你而言是新鮮的,我可以向你提供有關該鏈接的鏈接。 2)庫函數已經間接檢查了,爲什麼要複製這個檢查? 3)沒有什麼能阻止'shutil.copytree'函數在將來改進和管理這兩種情況。 4)Python中的例外情況並不特別;例如通過拋出StopIteration異常停止迭代。 – tzot 2010-01-03 20:27:58
那麼,在這種情況下處理異常需要6行,而檢查類型需要4行。沒有多少,但它最終加起來。另外,正如你所說,copytree可能有一天會很好地支持文件。但是不可能說出那個實現會是什麼樣子。也許它會在複製工作的某些情況下引發異常?在那種情況下,我的代碼會因爲增加的功能而突然停止工作。 但是你可能是對的,Python中的異常是相當通用的,我覺得很煩人,但這可能是因爲我似乎從來沒有習慣它 – pafcu 2010-01-04 14:18:23
的Unix cp
不「支持目錄和文件」:
betelgeuse:tmp james$ cp source/ dest/
cp: source/ is a directory (not copied).
爲了使CP複製目錄,你必須手動告訴CP,這是一個目錄,通過使用「-r」標誌。
儘管有一些斷開連接 - cp -r
當傳遞一個文件名作爲源將愉快地複製單個文件; copytree不會。
http://docs.python.org/library/shutil.html包含用於演示處理普通文件,符號鏈接和目錄的copytree()代碼。 – 2010-01-03 10:28:16
這個答案沒有解決這個問題。它應該是一個評論,而不是一個答案。 – 2017-02-15 11:51:37
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('..')
這段代碼很適合單獨檢查文件(檢查覆蓋問題),但不適用於二進制文件,如'zip'。爲什麼不使用簡單的python文件複製而不是逐行讀/寫? – notilas 2016-09-28 15:52:54
shutil.copy
和shutil.copy2
被複制文件。
shutil.copytree
複製一個包含所有文件和所有子文件夾的文件夾。 shutil.copytree
正在使用shutil.copy2
複製文件。
所以模擬cp -r
你說的是shutil.copytree
因爲cp -r
目標和拷貝一個文件夾,並像shutil.copytree
它的文件/子文件夾。沒有-r
cp
副本文件,如shutil.copy
和shutil.copy2
。
我認爲你不瞭解這個問題。試試'shutil.copytree('C:\ myfile.txt','C:\ otherfile')'。它不起作用。這就是OP在7年前所問的。 – 2017-02-15 15:09:23
當然,這是行不通的。像cp不適用於文件夾。你需要一個特殊的選擇。複製和副本樹是處理複製的最佳方式。如果copytree可以定位並存檔,那麼很容易出錯。你必須知道你在Linux和Python上都瞄準了什麼。那很難。再加上其他人在這裏評論它,但看到問題和答覆無法抗拒的答案。優雅的方式是知道你想做什麼,而不是沒有任何控制的通用副本。 – gms 2017-02-15 16:15:45
要添加到Tzot's和gns的答案,這裏是遞歸複製文件和文件夾的替代方法。 (Python的3.X)
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)
它應該是你第一次和你不知道如何遞歸複製文件和文件夾,我希望這有助於。
是的,這是一團糟。其中一個地方,通過試圖反映底層的系統調用,Python使可見接口變得更糟。雖然在複製文件和複製樹之間切換並不困難,但它不應該是必需的。也許可以在Python bug跟蹤器上提出增強請求,以允許'copytree'複製單個文件? – bobince 2010-01-03 12:35:25