2009-04-28 30 views
89

Tôi đang cố gắng viết một tập lệnh Python đơn giản sẽ sao chép index.tpl thành index.html trong tất cả các thư mục con (với một vài ngoại lệ).Cách lấy tất cả các thư mục con trực tiếp bằng Python

Tôi bị sa lầy bằng cách cố gắng lấy danh sách các thư mục con.

+8

Bạn có thể thấy rằng các câu trả lời được chấp nhận vào câu hỏi SO trước này giải quyết vấn đề: http://stackoverflow.com/questions/120656/directory-listing-in-python –

Trả lời

154
import os 
def get_immediate_subdirectories(a_dir): 
    return [name for name in os.listdir(a_dir) 
      if os.path.isdir(os.path.join(a_dir, name))] 
8

os.walk là bạn của bạn trong tình huống này.

Trực tiếp từ tài liệu:

đi bộ() tạo ra các tên tập tin trong một cây thư mục, bằng cách đi bộ cây hoặc từ trên xuống hoặc từ dưới lên. Đối với mỗi thư mục trong cây bắt nguồn từ đầu thư mục (bao gồm cả chính nó), nó tạo ra một 3-tuple (dirpath, dirnames, tên tập tin).

+1

Chỉ cần lưu ý rằng nếu bạn chỉ muốn các thư mục con cấp đầu tiên sau đó thoát khỏi sự lặp lại os.walk sau tập hợp các giá trị trả về đầu tiên. – yoyo

6

Sử dụng mô-đun filepath Twisted của:

from twisted.python.filepath import FilePath 

def subdirs(pathObj): 
    for subpath in pathObj.walk(): 
     if subpath.isdir(): 
      yield subpath 

if __name__ == '__main__': 
    for subdir in subdirs(FilePath(".")): 
     print "Subdirectory:", subdir 

Kể từ khi một số bình luận đã hỏi những ưu điểm của việc sử dụng thư viện Twisted của việc này là, tôi sẽ đi một chút vượt ra ngoài câu hỏi ban đầu ở đây.


some improved documentation trong nhánh giải thích những lợi thế của FilePath; bạn có thể muốn đọc điều đó.

Cụ thể hơn trong ví dụ này: không giống như phiên bản thư viện chuẩn, chức năng này có thể được triển khai với không nhập. Hàm "subdirs" là hoàn toàn chung chung, trong đó nó hoạt động trên không có gì ngoài lập luận của nó. Để sao chép và di chuyển tệp bằng thư viện chuẩn, bạn cần phải phụ thuộc vào nội trang "open", "listdir", có thể là "isdir" hoặc "os.walk" hoặc "shutil.copy". Có thể "os.path.join". Không phải đề cập đến thực tế là bạn cần một chuỗi thông qua một đối số để xác định các tập tin thực tế. Chúng ta hãy nhìn vào đầy đủ việc thực hiện mà sẽ sao chép "index.tpl" của mỗi thư mục để "index.html":

def copyTemplates(topdir): 
    for subdir in subdirs(topdir): 
     tpl = subdir.child("index.tpl") 
     if tpl.exists(): 
      tpl.copyTo(subdir.child("index.html")) 

Các "subdirs" chức năng trên có thể làm việc trên bất kỳ đối tượng FilePath -like. Có nghĩa là, trong số những thứ khác, ZipPath đối tượng. Thật không may ZipPath là chỉ đọc ngay bây giờ, nhưng nó có thể được mở rộng để hỗ trợ văn bản.

Bạn cũng có thể chuyển đối tượng của riêng mình cho mục đích thử nghiệm. Để kiểm tra các API sử dụng os.path được đề xuất ở đây, bạn phải sử dụng các tên đã nhập và các phụ thuộc ngầm và thường thực hiện phép màu đen để làm cho các thử nghiệm của bạn hoạt động. Với filepath, bạn làm điều gì đó như thế này:

class MyFakePath: 
    def child(self, name): 
     "Return an appropriate child object" 

    def walk(self): 
     "Return an iterable of MyFakePath objects" 

    def exists(self): 
     "Return true or false, as appropriate to the test" 

    def isdir(self): 
     "Return true or false, as appropriate to the test" 
... 
subdirs(MyFakePath(...)) 
+0

Vì tôi có ít tiếp xúc với Twisted, tôi luôn hoan nghênh các thông tin và ví dụ bổ sung; câu trả lời này là tốt đẹp để xem cho điều đó. Có nói rằng, vì cách tiếp cận này dường như đòi hỏi nhiều công việc hơn là sử dụng các mô-đun python tích hợp, và một cài đặt Xoắn, có lợi thế nào khi sử dụng điều này mà bạn có thể thêm vào câu trả lời không? –

+1

Câu trả lời của Glyph có lẽ được lấy cảm hứng từ thực tế là TwistedLore cũng sử dụng các tệp .tpl. – Constantin

+0

Vâng, rõ ràng tôi không mong đợi sự mua lại Tây Ban Nha :-) Tôi giả định "* .tpl" là một tham chiếu chung cho một số phần mở rộng trừu tượng có nghĩa là "mẫu", và không phải là một mẫu Twisted cụ thể (tôi đã nhìn thấy. nhiều ngôn ngữ sau khi tất cả). Tốt để biết. –

1

Dưới đây là một cách:

import os 
import shutil 

def copy_over(path, from_name, to_name): 
    for path, dirname, fnames in os.walk(path): 
    for fname in fnames: 
     if fname == from_name: 
     shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name)) 


copy_over('.', 'index.tpl', 'index.html') 
+0

-1: sẽ không hoạt động, vì shutil.copy sẽ sao chép vào thư mục hiện tại, vì vậy bạn sẽ kết thúc ghi đè 'index.html' trong thư mục hiện tại một lần cho mỗi 'index.tpl' bạn tìm thấy trong thư mục con . – nosklo

+0

Sửa mã, cảm ơn! –

2

tôi chỉ viết một số mã để di chuyển các máy ảo vmware xung quanh, và kết thúc bằng os.pathshutil để thực hiện sao chép tập tin giữa các thư mục con.

def copy_client_files (file_src, file_dst): 
    for file in os.listdir(file_src): 
      print "Copying file: %s" % file 
      shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file)) 

Nó không quá tao nhã, nhưng nó hoạt động.

13
import os, os.path 

Để có được (full-path) ngay lập tức thư mục con trong một thư mục:

def SubDirPath (d): 
    return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)]) 

Để có được mới nhất (mới nhất) thư mục con:

def LatestDirectory (d): 
    return max(SubDirPath(d), key=os.path.getmtime) 
46

Tại sao không có ai đề cập đến glob? glob cho phép bạn sử dụng mở rộng tên đường dẫn kiểu Unix, và là chức năng của tôi cho hầu hết mọi thứ cần tìm nhiều hơn một tên đường dẫn. Nó làm cho nó rất dễ dàng:

from glob import glob 
paths = glob('*/') 

Lưu ý rằng glob sẽ trở lại thư mục với dấu gạch chéo cuối cùng (như unix sẽ) trong khi hầu hết path giải pháp dựa sẽ bỏ qua các dấu gạch chéo thức.

+2

Giải pháp tốt, đơn giản và hoạt động. Đối với những người không muốn có dấu gạch chéo cuối cùng, anh ta có thể sử dụng 'đường dẫn = [p.replace ('/', '') này cho p trong glob ('* /')]'. –

+3

Có thể an toàn hơn khi chỉ cần cắt ký tự cuối cùng với '[p [: - 1] cho p trong đường dẫn] ', vì phương thức thay thế cũng sẽ thay thế bất kỳ dấu gạch chéo nào đã thoát trong tên tệp (không phải là các tên chung). – ari

+2

Thậm chí an toàn hơn, sử dụng dải ('/') để xóa dấu gạch chéo.Bằng cách này đảm bảo rằng bạn không cắt bất kỳ ký tự nào không bị gạch chéo –

9

Kiểm tra "Getting a list of all subdirectories in the current directory".

Dưới đây là một phiên bản Python 3:

import os 

dir_list = next(os.walk('.'))[1] 

print(dir_list) 
+0

. xóa nếu 'file_list' được thay thế bằng' dir_list', vì '[1]' trả về danh sách các dir. – wisbucky

+0

@ wisbucky điểm công bằng, tôi đã cập nhật câu trả lời của mình. –

+1

** Cực kỳ thông minh. ** Trong khi hiệu quả không quan trọng (_... nó hoàn toàn không_), tôi tò mò muốn biết điều này hay biểu thức trình tạo dựa trên glob '(s.rstrip ("/") cho s trong glob (parent_dir + "* /")) 'có nhiều thời gian hiệu quả hơn. Sự nghi ngờ trực quan của tôi là một giải pháp 'os (walk') 'dựa trên' stat() 'nên * nhanh hơn rất nhiều so với globbing kiểu vỏ. Đáng buồn thay, tôi thiếu ý chí để 'timeit' và thực sự tìm ra. –

6

Phương pháp này độc đáo sẽ làm tất cả trong một đi.

from glob import glob 
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")] 
Các vấn đề liên quan