Lặp lại qua các thư mục với Python


157

Tôi cần lặp lại thông qua các thư mục con của một thư mục nhất định và tìm kiếm các tập tin. Nếu tôi nhận được một tập tin, tôi phải mở nó và thay đổi nội dung và thay thế nó bằng các dòng của riêng tôi.

Tôi đã thử điều này:

import os

rootdir ='C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        f=open(file,'r')
        lines=f.readlines()
        f.close()
        f=open(file,'w')
        for line in lines:
            newline = "No you are not"
            f.write(newline)
        f.close()

nhưng tôi đang nhận được một lỗi. Tôi đang làm gì sai?


12
"Một lỗi" - cụ thể là lỗi gì?
Daniel Roseman

1
Xin vui lòng bạn có thể giải thích một chút về những gì bạn hy vọng sẽ làm với các tập tin / thư mục một khi bạn đi qua chúng làm việc như dự định? Ngoài ra xin vui lòng cung cấp chi tiết lỗi.
ChrisProsser

1
Thông báo lỗi mà tôi nhận được là không tìm thấy tệp cool.txt. Trong thư mục thử nghiệm của tôi, tôi có một thư mục khác gọi là src và trong thư mục src tôi có một thư mục khác gọi là main, trong thư mục này tôi có cool.txt
Wolf

4
bạn chỉ có thể viết lỗi trong câu hỏi? Thật khó chịu và không cần thiết phải đọc qua các bình luận để tìm thấy nó.
Charlie Parker

1
Hơn một năm sau tôi không thể tin rằng mình lại yêu cầu lỗi được đăng? @Wolf
Charlie Parker

Câu trả lời:


300

Việc đi bộ thực tế thông qua các thư mục hoạt động như bạn đã mã hóa nó. Nếu bạn thay thế nội dung của vòng lặp bên trong bằng một printcâu lệnh đơn giản, bạn có thể thấy rằng mỗi tệp được tìm thấy:

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print os.path.join(subdir, file)

Nếu bạn vẫn gặp lỗi khi chạy ở trên, vui lòng cung cấp thông báo lỗi.


Đã cập nhật cho Python3

import os
rootdir = 'C:/Users/sid/Desktop/test'

for subdir, dirs, files in os.walk(rootdir):
    for file in files:
        print(os.path.join(subdir, file))

1
C: / Users / sid / Desktop / test \ src \ app / cool.txt C: / Users / sid / Desktop / test \ src \ app / woohoo.txt Ya trong câu lệnh mở của mã của tôi, tôi nghĩ rằng tôi phải đưa ra đường dẫn tuyệt đối đến tập tin. import os rootdir = 'C: / Users / spemmara / Desktop / test / src / app /' cho subir, dirs, tập tin trong os.walk (rootdir): cho tệp trong tệp: f = open (subir + '/' + file , 'r') lines = f.readlines () f.close () f = open (subir + '/' + file, 'w') cho dòng trong dòng: newline = "hey i know" f.write (newline) f.close () Cảm ơn người đàn ông. Nó đã được giải quyết
Wolf

3
Chào! Xin lưu ý rằng "bản in" trong python 3 yêu cầu dấu ngoặc đơn, nếu không sẽ trả về lỗi cú pháp. Hi vọng điêu nay co ich!
Tommaso Di Noto

14

Một cách khác để trả lại tất cả tập tin trong thư mục con là sử dụng các pathlibmô-đun , được giới thiệu trong Python 3.4, cung cấp một cách tiếp cận hướng đối tượng để xử lý đường dẫn hệ thống tập tin (Pathlib cũng có sẵn trên Python 2.7 qua các mô-đun pathlib2 trên PyPi ):

from pathlib import Path

rootdir = Path('C:/Users/sid/Desktop/test')
# Return a list of regular files only, not directories
file_list = [f for f in rootdir.glob('**/*') if f.is_file()]

# For absolute paths instead of relative the current dir
file_list = [f for f in rootdir.resolve().glob('**/*') if f.is_file()]

Kể từ Python 3.5, globmô-đun cũng hỗ trợ tìm tệp đệ quy:

import os
from glob import iglob

rootdir_glob = 'C:/Users/sid/Desktop/test/**/*' # Note the added asterisks
# This will return absolute paths
file_list = [f for f in iglob('**/*', recursive=True) if os.path.isfile(f)]

Các file_listtừ một trong các phương pháp trên có thể được lặp qua mà không cần một vòng lặp lồng nhau:

for f in file_list:
    print(f) # Replace with desired operations

1
Điều gì thích hợp hơn ở đây cho Python 3.6?
PhoenixDev

@PhoenixDev Tôi chưa nghe nói về một phương pháp được khuyến nghị so với phương pháp khác nói chung. Tôi thích sử dụng pathlibbản thân mình, chủ yếu là vì tôi thích cú pháp hướng đối tượng. Có những khác biệt khác, chẳng hạn như thư viện đường dẫn trả về các lớp đường dẫn cụ thể thay vì các chuỗi và các hàm có sẵn khác nhau giữa các thư viện (ví dụ os.path.expanduser('~')vs Path.home()). Duyệt qua các tài liệu và xem cách tiếp cận bạn thích.
joelostblom

Thay vì thêm **vào mô hình toàn cầu, bạn có thể sử dụng rglob.
Georgy

12

Tính đến năm 2020 , glob.iglob(path/**, recursive=True)dường như là giải pháp pythonic nhất , tức là:

import glob, os

for filename in glob.iglob('/pardadox-music/**', recursive=True):
    if os.path.isfile(filename): # filter dirs
        print(filename)

Đầu ra:

/pardadox-music/modules/her1.mod
/pardadox-music/modules/her2.mod
...

Ghi chú:
1 - global.iglob

glob.iglob(pathname, recursive=False)

Trả về một trình vòng lặp mang lại các giá trị giống như glob()mà không thực sự lưu trữ tất cả chúng cùng một lúc.

2 - Nếu đệ quy là True, mẫu '**'sẽ khớp với bất kỳ tệp nào và không hoặc nhiều hơn directoriessubdirectories.

3 - Nếu thư mục chứa các tệp bắt đầu với  .chúng sẽ không được khớp theo mặc định. Ví dụ, hãy xem xét một thư mục chứa  card.gif và .card.gif:

>>> import glob
>>> glob.glob('*.gif') ['card.gif'] 
>>> glob.glob('.c*')['.card.gif']

4 - Bạn cũng có thể sử dụng rglob(pattern), mà là giống như gọi  glob() với **/thêm ở phía trước của mô hình tương đối nhất định.


1
Đây pythonic giải pháp không liệt kê các file ẩn (aka dotfiles) trong khi một được chấp nhận không.
ashrasmun

@ashrasmun gì bạn đề cập đến được giải thích trong docs.python.org/3/library/glob.html
CONvid19
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.