10

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

12

Проблема с рекурсивным перечислением файлов в директории

Я хочу рекурсивно перечислить все файлы в определенной директории. У меня есть следующая структура директорий:

  • 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 ответ(ов)

1

Вы можете использовать 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)

Использование генератора позволяет обрабатывать каждый файл по мере его нахождения, вместо того чтобы сначала находить все файлы, а затем обрабатывать их. Это может быть особенно полезно при работе с большими объемами данных, так как позволяет сократить использование памяти.

0

Вы можете использовать модифицированную версию модуля glob, которая поддерживает синтаксис ** для рекурсивного поиска. Для этого вам нужно установить модуль glob2. Пример использования:

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

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

0

Вы можете использовать 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.

0

Вот решение с использованием вложенных генераторов списков, 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')

Этот подход позволяет эффективно искать файлы с определенным суффиксом или по заданному шаблону в подкаталогах.

0

Ваш код использует модуль glob для поиска файлов с расширением .c в указанной директории и всех её поддиректориях. Давайте разберём, что делает каждая из строк, связанной с glob.glob():

  1. glob.glob('*.c'): Находит все файлы, заканчивающиеся на .c, в текущей директории.
  2. glob.glob('*/*.c'): Находит все файлы, заканчивающиеся на .c, находящиеся в непосредственных поддиректориях текущей директории.
  3. glob.glob('**/*.c'): Находит все файлы с расширением .c, только в поддиректориях, но не в текущей директории.
  4. glob.glob('*.c', recursive=True): То же самое, что и первый пункт, так как с recursive=True поиск происходит только в текущей директории.
  5. glob.glob('*/*.c', recursive=True): Находит все .c файлы в поддиректориях, аналогично третьему пункту.
  6. glob.glob('**/*.c', recursive=True): Находит все файлы с расширением .c как в текущей директории, так и во всех поддиректориях.

Таким образом, ваш код корректно выводит полные пути к найденным файлам и их имена без учёта пути.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь