2015-02-09 15 views
7

Tôi đang cố gắng viết một hàm Python sẽ đệ quy xóa tất cả các thư mục trống. Điều này có nghĩa là nếu thư mục "a" chỉ chứa "b", "b" nên bị xóa, thì "a" sẽ bị xóa (vì nó không chứa gì cả). Nếu một thư mục chứa bất cứ thứ gì, nó sẽ bị bỏ qua. Minh họa:Tại sao os.walk của python() không phản ánh việc xóa thư mục?

top/a/b/ 
top/c/d.txt 
top/c/foo/ 

Vì điều này, ba thư mục "b", "a", và "foo" nên bị xóa, như "foo" và "b" là trống bây giờ, và "a" sẽ trở nên trống rỗng sau khi xóa "b".

Tôi đang cố thực hiện điều này qua os.walkshutil.rmtree. Thật không may, mã của tôi chỉ xóa cấp thư mục đầu tiên, nhưng không chỉ xóa các thư mục mới trong quá trình này.

Tôi đang sử dụng thông số topdown=false của os.walk. documentation cho os.walk nói rằng "Nếu topdown là Sai, ba cho thư mục được tạo sau khi ba cho tất cả các thư mục con của nó (thư mục được tạo từ dưới lên)." Đó không phải là những gì tôi thấy.

Dưới đây là mã của tôi:

for root, dirs, files in os.walk(".", topdown=False): 
    contents = dirs+files 
    print root,"contains:",contents 
    if len(contents) == 0: 
    print 'Removing "%s"'%root 
    shutil.rmtree(root) 
    else: 
    print 'Not removing "%s". It has:'%root,contents 

Nếu tôi đã cấu trúc thư mục được mô tả ở trên, đây là những gì tôi nhận được:

./c/foo contains: [] 
Removing "./c/foo" 
./c contains: ['foo', 'd.txt'] 
Not removing "./c". It has: ['foo', 'd.txt'] 
./a/b contains: [] 
Removing "./a/b" 
./a contains: ['b'] 
Not removing "./a". It has: ['b'] 
. contains: ['c', 'a'] 
Not removing ".". It has: ['c', 'a'] 

Lưu ý rằng, mặc dù tôi đã gỡ bỏ "b", " một "không được loại bỏ, nghĩ rằng nó vẫn còn chứa" b ". Những gì tôi đang bối rối về là tài liệu cho os.walk nói rằng nó tạo ra ba cho "./a" sau khi tạo ra ba cho "b". Đầu ra của tôi cho thấy nếu không. Câu chuyện tương tự cho "./c". Nó cho thấy rằng nó vẫn còn "foo", mặc dù tôi đã xóa nó ngay ra khỏi cổng.

Tôi đang làm gì sai? (Tôi đang sử dụng Python 2.6.6.)

+0

Tôi không mong đợi os.đi bộ để được cập nhật trên mỗi lần lặp của vòng lặp 'for' – jcfollower

+0

Tôi đoán đó là chìa khóa. "Trước" và "sau" trong tài liệu tham chiếu đến thứ tự trong kết quả mảng kết quả bằng 'os.walk()', không phải là một thứ tự thời gian của các lần lặp liên tiếp thông qua vòng lặp 'for'. Thực tế là người gọi, trong chế độ 'topdown = True', có thể sửa đổi đối số' dirnames' khiến tôi nghĩ rằng việc lặp lại có thể bị ảnh hưởng. – seanahern

Trả lời

2

jcfollower là hoàn toàn chính xác về nguyên nhân của vấn đề bạn đang gặp phải: Hệ thống tập tin được luôn đọc từ trên xuống dưới, ngay cả khi kết quả được mang lại từ os.walk một cách từ dưới lên. Điều này có nghĩa là các sửa đổi hệ thống tập tin bạn thực hiện sẽ không được phản ánh trong các kết quả sau này.

Một giải pháp cho vấn đề này là để duy trì một bộ các thư mục bị xóa, do đó bạn có thể lọc chúng ra khỏi danh sách của cha mẹ của thư mục con:

removed = set()            # first new line 
for root, dirs, files in os.walk(".", topdown=False): 
     dirs = [dir for dir in dirs if os.path.join(root, dir) not in removed] # second 
     contents = dirs+files 
     print root,"contains:",contents 
     if len(contents) == 0: 
      print 'Removing "%s"'%root 
      shutil.rmtree(root) 
      removed.add(root)         # third new line 
     else: 
      print 'Not removing "%s". It has:'%root,contents 

Có ba dòng mới. Đầu tiên, ở trên cùng, tạo một tập hợp trống removed để chứa các thư mục đã bị xóa. Thứ hai thay thế danh sách dirs bằng danh sách mới không bao gồm bất kỳ thư mục con nào trong tập hợp đã xóa, vì chúng đã bị xóa trong bước trước. Dòng mới cuối cùng thêm thư mục hiện tại vào tập hợp khi đã bị xóa.

+0

Đó là một mẹo nhỏ gọn! Rất thông minh. Nó thừa nhận rằng 'os.walk()' sẽ cung cấp cho bạn thông tin có thể đã bị vô hiệu hóa bởi việc xóa và sửa đổi rõ ràng những gì nó trả về. – seanahern

9

Các documentation có này ...

Không có vấn đề giá trị của topdown, danh sách các thư mục con được lấy ra trước khi các bộ cho thư mục và nó thư mục con được tạo. câu trả lời

+0

Đây là câu trả lời tốt nhất cho đến nay. Nó nói rằng 'topdown = False' trở thành chủ yếu là một câu hỏi đặt hàng dữ liệu trong đầu ra của' os.walk() ', không phải thứ tự thời gian của việc khám phá hệ thống tập tin cơ bản. – seanahern

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