Вопрос-Ответ

How to use to find files recursively?

Как использовать для рекурсивного поиска файлов?

Я хотел бы рекурсивно перечислить все файлы в каталоге. В настоящее время у меня есть структура каталогов, подобная этой:


  • src/main.c

  • src/dir/file1.c

  • src/another-dir/file2.c

  • src/another-dir/nested/files/file3.c

Я попытался сделать следующее:

from glob import glob

glob(os.path.join('src','*.c'))

Но при этом будут получены только файлы be непосредственно в src подпапке, например, я получу, main.c но я не получу file1.c, file2.c и т.д.

from glob import glob

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

Но это, очевидно, ограничено и неуклюже, как я могу сделать это правильно?

Переведено автоматически
Ответ 1

Есть несколько способов:

pathlib.Path().rglob()

Используйте pathlib.Path().rglob() из pathlib модуля, который был представлен в Python 3.5.

from pathlib import Path

for path in Path('src').rglob('*.c'):
print(path.name)

glob.glob()

Если вы не хотите использовать pathlib, используйте glob.glob():

from glob import glob

for filename in glob('src/**/*.c', recursive=True):
print(filename)

Для случаев, когда совпадающие файлы начинаются с точки (.); например, файлы в текущем каталоге или скрытые файлы в системе на базе Unix, используйте os.walk() решение ниже.

os.walk()

Для старых версий Python используйте os.walk() для рекурсивного обхода каталога и fnmatch.filter() для сопоставления с простым выражением:

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
for filename in fnmatch.filter(filenames, '*.c'):
matches.append(os.path.join(root, filename))

Эта версия также должна быть быстрее в зависимости от того, сколько у вас файлов, поскольку модуль pathlib имеет небольшие накладные расходы os.walk().

Ответ 2

Для python >= 3.5 вы можете использовать **, recursive=True, т.е.:

import glob
for f in glob.glob('/path/**/*.c', recursive=True):
print(f)


Если recursive имеет значение True (по умолчанию False), шаблон ** будет соответствовать любым файлам и нулю или более directories и subdirectories. Если шаблону следует
an os.sep, совпадают только каталоги и subdirectories.



Демонстрация Python 3

Ответ 3

Аналогично другим решениям, но с использованием fnmatch.fnmatch вместо glob, начиная с os.walk уже перечислил имена файлов:

import os, fnmatch


def find_files(directory, pattern):
for root, dirs, files in os.walk(directory):
for basename in files:
if fnmatch.fnmatch(basename, pattern):
filename = os.path.join(root, basename)
yield filename


for filename in find_files('src', '*.c'):
print 'Found C source:', filename

Кроме того, использование генератора позволяет обрабатывать каждый файл по мере его нахождения, вместо поиска всех файлов и последующей их обработки.

Ответ 4

Я модифицировал модуль glob для поддержки ** рекурсивного глобулирования, например:

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/

Полезно, когда вы хотите предоставить своим пользователям возможность использовать синтаксис **, и, следовательно, одного os.walk() недостаточно.

2023-09-08 02:30 python