Làm cách nào để tôi có thể tìm kiếm các thư mục con bằng cách sử dụng mô-đun global.glob?


107

Tôi muốn mở một loạt các thư mục con trong một thư mục và tìm một số tệp văn bản và in một số dòng của tệp văn bản. Tôi đang sử dụng cái này:

configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt')

Nhưng điều này cũng không thể truy cập các thư mục con. Có ai biết cách tôi có thể sử dụng cùng một lệnh để truy cập các thư mục con không?


Câu trả lời:


163

Trong Python 3.5 và mới hơn, sử dụng **/chức năng đệ quy mới :

configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True)

Khi recursiveđược đặt, **theo sau là dấu phân cách đường dẫn khớp với 0 hoặc nhiều thư mục con.

Trong các phiên bản Python trước, glob.glob() không thể liệt kê các tệp trong thư mục con một cách đệ quy.

Trong trường hợp đó, tôi sẽ sử dụng os.walk()kết hợp với fnmatch.filter():

import os
import fnmatch

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in fnmatch.filter(files, '*.txt')]

Thao tác này sẽ duyệt đệ quy các thư mục của bạn và trả về tất cả các tên đường dẫn tuyệt đối cho .txtcác tệp phù hợp . Trong trường hợp cụ thể này, fnmatch.filter()có thể là quá mức cần thiết, bạn cũng có thể sử dụng một .endswith()bài kiểm tra:

import os

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in files if f.endswith('.txt')]

3
Tôi có thể thấy: global.glob ('/ path to directory / * / *. Txt ") phù hợp với tôi. Đây là cách cơ bản sử dụng quy tắc Unix shell.
Surya

7
@ User123: không liệt kê các thư mục một cách đệ quy . Bạn đang liệt kê tất cả các tệp văn bản sâu một cấp , nhưng không nằm trong các thư mục con khác hoặc thậm chí trực tiếp trong path to directory.
Martijn Pieters

1
Điều này không hoàn toàn liên quan, nhưng tại sao cài đặt recursive=Falsecùng với **/ chức năng không cung cấp danh sách các tệp chỉ trong thư mục nhất định mà lại nằm trong các tệp con của nó?
Dr_Zaszuś

@ Dr_Zaszuś: xin lỗi? **/cung cấp danh sách các tên thư mục trong thư mục đang làm việc hiện tại, bởi vì mẫu kết thúc bằng /recursive=Falsevề cơ bản với bạn có một đôi *, khớp giống như */, chỉ kém hiệu quả hơn.
Martijn Pieters

@ Dr_Zaszuś: sử dụng */*nếu bạn cần tất cả các tệp trong tất cả các thư mục con.
Martijn Pieters

22

Để tìm tệp trong thư mục con ngay lập tức:

configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt')

Đối với phiên bản đệ quy duyệt qua tất cả các thư mục con, bạn có thể sử dụng **và chuyển recursive=True từ Python 3.5 :

configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True)

Cả hai hàm đều trả về danh sách. Bạn có thể sử dụng glob.iglob()để trả về từng đường dẫn một. Hoặc sử dụngpathlib :

from pathlib import Path

path = Path(r'C:\Users\sam\Desktop')
txt_files_only_subdirs = path.glob('*/*.txt')
txt_files_all_recursively = path.rglob('*.txt') # including the current dir

Cả hai phương thức đều trả về các trình vòng lặp (bạn có thể lấy từng đường dẫn một).


Vâng, tôi hiểu điều đó; nhưng tôi cũng không mong đợi glob()để hỗ trợ các mẫu trong thư mục.
Martijn Pieters

Nhận xét đã bị xóa, tôi thấy bây giờ nó đã đưa ra ấn tượng sai; bên cạnh đó, bản vá bao gồm một bản cập nhật tài liệu cho **trường hợp đệ quy. Nhưng **để hoạt động, bạn phải thiết lập công recursion=Truetắc, btw.
Martijn Pieters

20

Có rất nhiều sự nhầm lẫn về chủ đề này. Hãy để tôi xem nếu tôi có thể làm rõ nó (Python 3.7):

  1. glob.glob('*.txt') :khớp với tất cả các tệp kết thúc bằng '.txt' trong thư mục hiện tại
  2. glob.glob('*/*.txt') :giống như 1
  3. glob.glob('**/*.txt') :chỉ khớp với tất cả các tệp kết thúc bằng '.txt' trong các thư mục con ngay lập tức , nhưng không hiện tại
  4. glob.glob('*.txt',recursive=True) :giống như 1
  5. glob.glob('*/*.txt',recursive=True) :giống như 3
  6. glob.glob('**/*.txt',recursive=True):khớp với tất cả các tệp kết thúc bằng '.txt' trong thư mục hiện tại và trong tất cả các thư mục con

Vì vậy, tốt nhất là luôn chỉ định recursive=True.


1
Đây phải là câu trả lời hàng đầu!
Abhik Sarkar

17

Các glob2 gói hỗ trợ thẻ hoang dã và là hợp lý nhanh chóng

code = '''
import glob2
glob2.glob("files/*/**")
'''
timeit.timeit(code, number=1)

Trên máy tính xách tay của tôi, mất khoảng 2 giây để khớp > 60.000 đường dẫn tệp .


9

Bạn có thể sử dụng Formic với Python 2.6

import formic
fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/")

Tiết lộ - Tôi là tác giả của gói này.


4

Đây là phiên bản đã điều chỉnh cho phép glob.globchức năng giống như mà không cần sử dụng glob2.

def find_files(directory, pattern='*'):
    if not os.path.exists(directory):
        raise ValueError("Directory not found {}".format(directory))

    matches = []
    for root, dirnames, filenames in os.walk(directory):
        for filename in filenames:
            full_path = os.path.join(root, filename)
            if fnmatch.filter([full_path], pattern):
                matches.append(os.path.join(root, filename))
    return matches

Vì vậy, nếu bạn có cấu trúc dir sau

tests/files
├── a0
   ├── a0.txt
   ├── a0.yaml
   └── b0
       ├── b0.yaml
       └── b00.yaml
└── a1

Bạn có thể làm điều gì đó như thế này

files = utils.find_files('tests/files','**/b0/b*.yaml')
> ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml']

Khá nhiều fnmatchmẫu khớp trên toàn bộ tên tệp, thay vì chỉ tên tệp.


2

configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")

Không hoạt động cho tất cả các trường hợp, thay vào đó hãy sử dụng global2

configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt")

2

Nếu bạn có thể cài đặt gói cầu nối ...

import glob2
filenames = glob2.glob("C:\\top_directory\\**\\*.ext")  # Where ext is a specific file extension
folders = glob2.glob("C:\\top_directory\\**\\")

Tất cả tên tệp và thư mục:

all_ff = glob2.glob("C:\\top_directory\\**\\**")  

2

Nếu bạn đang chạy Python 3.4+, bạn có thể sử dụng pathlibmô-đun. Các Path.glob()phương pháp hỗ trợ các **mô hình, mà có nghĩa là “thư mục này và tất cả các thư mục con, đệ quy”. Nó trả về một trình tạo ra Pathcác đối tượng cho tất cả các tệp phù hợp.

from pathlib import Path
configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt")

0

Như đã chỉ ra bởi Martijn, global chỉ có thể thực hiện điều này thông qua **toán tử được giới thiệu trong Python 3.5. Vì OP đã yêu cầu rõ ràng về mô-đun toàn cầu, phần sau sẽ trả về một trình lặp đánh giá lười biếng hoạt động tương tự

import os, glob, itertools

configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
                         for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))

Lưu ý rằng bạn chỉ có thể lặp lại một lần configfilestrong cách tiếp cận này. Nếu bạn yêu cầu một danh sách thực các cấu hình có thể được sử dụng trong nhiều hoạt động, bạn sẽ phải tạo điều này một cách rõ ràng bằng cách sử dụng list(configfiles).


0

Lệnh rglobsẽ thực hiện một đệ quy vô hạn xuống cấp con sâu nhất của cấu trúc thư mục của bạn. Tuy nhiên, nếu bạn chỉ muốn sâu một cấp thì không nên sử dụng nó.

Tôi nhận ra OP đã nói về việc sử dụng global.glob. Tuy nhiên, tôi tin rằng điều này giải đáp được mục đích là tìm kiếm tất cả các thư mục con một cách đệ quy.

Các rglobchức năng thời gian gần đây đã tạo ra một sự gia tăng 100x tốc độ cho một thuật toán xử lý dữ liệu được sử dụng cấu trúc thư mục như một giả định cố định cho thứ tự của dữ liệu đọc. Tuy nhiên, với việc rglobchúng tôi có thể thực hiện một lần quét một lần qua tất cả các tệp tại hoặc bên dưới một thư mục mẹ được chỉ định, lưu tên của chúng vào danh sách (hơn một triệu tệp), sau đó sử dụng danh sách đó để xác định tệp chúng tôi cần mở ở bất kỳ trong tương lai chỉ dựa trên quy ước đặt tên tệp so với thư mục mà chúng đã ở.

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.