2010-01-03 85 views
91

Python có chức năng sao chép tệp (ví dụ: shutil.copy) và chức năng sao chép các thư mục (ví dụ: shutil.copytree) nhưng tôi không tìm thấy bất kỳ chức năng nào xử lý cả hai. Chắc chắn, nó tầm thường để kiểm tra xem bạn có muốn sao chép một tập tin hoặc một thư mục, nhưng nó có vẻ như một sự thiếu sót kỳ lạ.Sao chép tệp hoặc thư mục đệ quy bằng Python

Có thực sự không có hàm chuẩn nào hoạt động như lệnh unix cp -r, tức là hỗ trợ cả thư mục và tệp và bản sao đệ quy? Điều gì sẽ là cách thanh lịch nhất để giải quyết vấn đề này bằng Python?

+3

Vâng, đây là một mớ hỗn độn. Một trong những nơi mà, bằng cách cố gắng phản ánh các cuộc gọi hệ thống cơ bản, Python làm cho giao diện nhìn thấy tồi tệ hơn. Mặc dù nó không khó để chuyển đổi giữa copy-file và copy-tree, nó không cần thiết. Có thể gửi yêu cầu nâng cao trên trình theo dõi lỗi Python để cho phép 'copytree' sao chép một tệp? – bobince

Trả lời

109

Tôi đề nghị trước tiên bạn gọi shutil.copytree và nếu ngoại lệ bị ném, hãy thử lại với 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 
+13

Tôi nghĩ rằng nó sẽ được sạch hơn nhiều để chỉ đơn giản là kiểm tra xem src là một thư mục bằng cách sử dụng os.path.isdir (src) thay vì bắt một ngoại lệ như thế này. Hoặc là có một số lý do đặc biệt người ta nên sử dụng một ngoại lệ ở đây để thay thế? – pafcu

+23

1) Bởi vì trong thế giới Python EAFP (nó dễ dàng hơn để yêu cầu sự tha thứ hơn sự cho phép) được ưa thích để LBYL (nhìn trước khi bạn nhảy).Tôi có thể cung cấp cho bạn các liên kết về điều đó, nếu nó có vẻ mới đối với bạn. 2) Các chức năng thư viện đã gián tiếp kiểm tra cho điều đó, vậy tại sao tái tạo kiểm tra? 3) không có gì dừng chức năng 'shutil.copytree' để cải thiện và quản lý cả hai trường hợp trong tương lai. 4) Ngoại lệ không phải là ngoại lệ trong Python; ví dụ. một phép lặp dừng lại bằng cách ném một ngoại lệ StopIteration. – tzot

+2

Vâng, trong trường hợp này xử lý ngoại lệ có 6 dòng, trong khi kiểm tra loại mất 4 dòng. Không nhiều, nhưng cuối cùng nó cũng tăng thêm. Ngoài ra, như bạn nói, copytree một ngày nào đó cũng hỗ trợ rất tốt các tệp. Nhưng không thể nói được việc thực hiện đó sẽ như thế nào. Có lẽ nó ném một ngoại lệ trong một số trường hợp bản sao hoạt động? Trong trường hợp đó, mã của tôi đột nhiên ngừng hoạt động chỉ vì chức năng được thêm vào. Nhưng bạn có lẽ đúng, ngoại lệ là khá commong trong Python, một cái gì đó mà tôi thấy rất khó chịu, nhưng nó có lẽ vì tôi không bao giờ dường như quen với nó – pafcu

3

Unix cp không 'hỗ trợ cả hai thư mục và các tập tin':

betelgeuse:tmp james$ cp source/ dest/ 
cp: source/ is a directory (not copied). 

Để làm cp sao chép một thư mục, bạn phải tự nói với cp rằng đó là một thư mục, bằng cách sử dụng lá cờ '-r' .

Có một số ngắt kết nối tại đây mặc dù - cp -r khi truyền tên tệp vì nguồn sẽ chỉ sao chép một cách vui vẻ vào một tệp duy nhất; copytree sẽ không.

+2

http://docs.python.org/library/shutil.html bao gồm mã cho copytree() thể hiện việc xử lý các tệp, liên kết tượng trưng và thư mục thông thường. –

+1

Câu trả lời này không giải quyết được câu hỏi. Nó phải là một bình luận, không phải là một câu trả lời. –

-1

Phương pháp python shutil.copytree là mớ hỗn độn. Tôi đã thực hiện một trong những hoạt động chính xác:

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('..') 
+1

Mã này rất phù hợp để kiểm tra tệp riêng lẻ (kiểm tra vấn đề ghi đè), nhưng sẽ không hoạt động đối với các tệp nhị phân như 'zip'. Tại sao không sử dụng sao chép tập tin python đơn giản thay vì dòng bởi đọc/ghi? – notilas

1

shutil.copyshutil.copy2 đang sao chép tập tin.

shutil.copytree sao chép thư mục có tất cả các tệp và tất cả các thư mục con. shutil.copytree đang sử dụng shutil.copy2 để sao chép các tệp.

Vì vậy, tương tự với cp -r bạn đang nói là shutil.copytree vì mục tiêu cp -r và sao chép thư mục và tệp/thư mục con của nó như shutil.copytree. Không có các tệp -rcp sao chép như shutil.copyshutil.copy2.

+0

Tôi không nghĩ bạn đã hiểu câu hỏi. Hãy thử 'shutil.copytree ('C: \ myfile.txt', 'C: \ otherfile')'. Nó không hoạt động. Đó là những gì OP hỏi về ... 7 năm trước. –

+0

Tất nhiên nó không hoạt động. Giống như cp không hoạt động với các thư mục. Bạn cần một tùy chọn đặc biệt. copy và copytree là cách tốt nhất để xử lý việc sao chép. Nếu copytree có thể nhắm mục tiêu và các tập tin thì sẽ dễ mắc lỗi. Bạn phải biết những gì bạn đang nhắm mục tiêu cả với Linux và Python. Thật khó. Thêm một người khác đã nhận xét nó ở đây, nhưng nhìn thấy câu hỏi và câu trả lời không thể cưỡng lại câu trả lời. Cách thanh lịch là để biết những gì bạn muốn làm và không phải là một bản sao phổ quát mà không có bất kỳ kiểm soát. – gms

3

Để thêm Tzot'sgns câu trả lời, đây là cách thay thế sao chép tệp và thư mục đệ quy. (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) 

Đây có phải là lần đầu tiên bạn không biết cách sao chép tệp và thư mục đệ quy, tôi hy vọng điều này sẽ hữu ích.

Các vấn đề liên quan