Как использовать для поиска файлов рекурсивно?
Проблема с рекурсивным перечислением файлов в директории
Я хочу рекурсивно перечислить все файлы в определенной директории. У меня есть следующая структура директорий:
src/main.c
src/dir/file1.c
src/another-dir/file2.c
src/another-dir/nested/files/file3.c
Я попытался сделать следующее:
from glob import glob
import os
glob(os.path.join('src', '*.c'))
Но это решение возвращает только файлы, находящиеся непосредственно в подпапке src
, т.е. я получаю main.c
, но не получаю file1.c
, file2.c
и т.д.
Я также пробовал:
from glob import glob
import os
glob(os.path.join('src', '*.c'))
glob(os.path.join('src', '*', '*.c'))
glob(os.path.join('src', '*', '*', '*.c'))
glob(os.path.join('src', '*', '*', '*', '*.c'))
Однако это явно ограниченное и громоздкое решение. Как я могу сделать это правильно, чтобы перечислить все файлы с расширением .c
во всех подкаталогах?
5 ответ(ов)
Вы можете использовать fnmatch.fnmatch
, чтобы фильтровать файлы по шаблону, вместо glob
, так как os.walk
уже возвращает список файлов. Вот пример функции, которая делает это:
import os
import 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)
Использование генератора позволяет обрабатывать каждый файл по мере его нахождения, вместо того чтобы сначала находить все файлы, а затем обрабатывать их. Это может быть особенно полезно при работе с большими объемами данных, так как позволяет сократить использование памяти.
Вы можете использовать модифицированную версию модуля glob, которая поддерживает синтаксис **
для рекурсивного поиска. Для этого вам нужно установить модуль glob2
. Пример использования:
>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')
Этот подход особенно полезен, если вы хотите предоставить своим пользователям возможность использовать синтаксис **
, так как стандартный os.walk()
может не удовлетворять всем требованиям. Вы можете найти код и дополнительные сведения о данном модуле на GitHub.
Вы можете использовать os.walk
, чтобы собрать имена файлов, соответствующие вашим критериям. Например:
import os
cfiles = []
for root, dirs, files in os.walk('src'):
for file in files:
if file.endswith('.c'):
cfiles.append(os.path.join(root, file))
Этот код проходит по всем папкам и файлам в каталоге src
рекурсивно. Если файл заканчивается на .c
, он добавляет полный путь к этому файлу в список cfiles
.
Вот решение с использованием вложенных генераторов списков, os.walk
и простого сопоставления суффиксов вместо glob
:
import os
cfiles = [os.path.join(root, filename)
for root, dirnames, filenames in os.walk('src')
for filename in filenames if filename.endswith('.c')]
Это можно сжать до однострочника:
import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]
Или обобщить в виде функции:
import os
def recursive_glob(rootdir='.', suffix=''):
return [os.path.join(looproot, filename)
for looproot, _, filenames in os.walk(rootdir)
for filename in filenames if filename.endswith(suffix)]
cfiles = recursive_glob('src', '.c')
Если вам нужны полные шаблоны в стиле glob
, вы можете воспользоваться примерами Алекса и Бруно и использовать fnmatch
:
import fnmatch
import os
def recursive_glob(rootdir='.', pattern='*'):
return [os.path.join(looproot, filename)
for looproot, _, filenames in os.walk(rootdir)
for filename in filenames
if fnmatch.fnmatch(filename, pattern)]
cfiles = recursive_glob('src', '*.c')
Этот подход позволяет эффективно искать файлы с определенным суффиксом или по заданному шаблону в подкаталогах.
Ваш код использует модуль glob
для поиска файлов с расширением .c
в указанной директории и всех её поддиректориях. Давайте разберём, что делает каждая из строк, связанной с glob.glob()
:
glob.glob('*.c')
: Находит все файлы, заканчивающиеся на.c
, в текущей директории.glob.glob('*/*.c')
: Находит все файлы, заканчивающиеся на.c
, находящиеся в непосредственных поддиректориях текущей директории.glob.glob('**/*.c')
: Находит все файлы с расширением.c
, только в поддиректориях, но не в текущей директории.glob.glob('*.c', recursive=True)
: То же самое, что и первый пункт, так как сrecursive=True
поиск происходит только в текущей директории.glob.glob('*/*.c', recursive=True)
: Находит все.c
файлы в поддиректориях, аналогично третьему пункту.glob.glob('**/*.c', recursive=True)
: Находит все файлы с расширением.c
как в текущей директории, так и во всех поддиректориях.
Таким образом, ваш код корректно выводит полные пути к найденным файлам и их имена без учёта пути.
Как создать каталог и все отсутствующие родительские каталоги?
Извлечение имени файла из пути независимо от формата ОС/пути
Как получить имя файла без расширения из пути в Python?
Функциональность mkdir -p в Python
Как получить абсолютный путь к файлу в Python