Как использовать glob () для рекурсивного поиска файлов? - PullRequest
622 голосов
/ 02 февраля 2010

Вот что у меня есть:

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

но я хочу найти подпапки в src. Примерно так будет работать:

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

Но это явно ограничено и неуклюже.

Ответы [ 23 ]

3 голосов
/ 14 сентября 2011

Еще один способ сделать это, используя только модуль glob. Просто заполните метод rglob начальным базовым каталогом и шаблоном для сопоставления, и он вернет список совпадающих имен файлов.

import glob
import os

def _getDirs(base):
    return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]

def rglob(base, pattern):
    list = []
    list.extend(glob.glob(os.path.join(base,pattern)))
    dirs = _getDirs(base)
    if len(dirs):
        for d in dirs:
            list.extend(rglob(os.path.join(base,d), pattern))
    return list
2 голосов
/ 05 декабря 2015

В дополнение к предлагаемым ответам вы можете сделать это с помощью некоторого ленивого поколения и магии понимания списка:

import os, glob, itertools

results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c'))
                                               for root, dirs, files in os.walk('src'))

for f in results: print(f)

Помимо размещения в одну строку и исключения ненужных списков в памяти, у этого также есть приятный побочный эффект, который вы можете использовать аналогично оператору **, например, вы можете использовать os.path.join(root, 'some/path/*.c'), чтобы получить все файлы .c во всех подкаталогах src, которые имеют эту структуру.

2 голосов
/ 02 августа 2013

Тот использует fnmatch или регулярное выражение:

import fnmatch, os

def filepaths(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            try:
                matched = pattern.match(basename)
            except AttributeError:
                matched = fnmatch.fnmatch(basename, pattern)
            if matched:
                yield os.path.join(root, basename)

# usage
if __name__ == '__main__':
    from pprint import pprint as pp
    import re
    path = r'/Users/hipertracker/app/myapp'
    pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
    pp([x for x in filepaths(path, '*.py')])
2 голосов
/ 27 июля 2013

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

Но я не использовал fnmatch или walk

#!/usr/bin/python

import os,glob,sys

def dirlist(path, c = 1):

        for i in glob.glob(os.path.join(path, "*")):
                if os.path.isfile(i):
                        filepath, filename = os.path.split(i)
                        print '----' *c + filename

                elif os.path.isdir(i):
                        dirname = os.path.basename(i)
                        print '----' *c + dirname
                        c+=1
                        dirlist(i,c)
                        c-=1


path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)
1 голос
/ 18 августа 2014

Вот мое решение, использующее списочный анализ для поиска нескольких расширений файлов рекурсивно в каталоге и во всех подкаталогах:

import os, glob

def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions 
    Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
    with .jpg and .JPG

    Parameters
    ----------
    path : str
        A directory name
    exts : tuple
        File extensions to glob for

    Returns
    -------
    files : list
        list of files matching extensions in exts in path and subfolders

    """
    dirs = [a[0] for a in os.walk(path)]
    f_filter = [d+e for d in dirs for e in exts]    
    return [f for files in [glob.iglob(files) for files in f_filter] for f in files]

my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
    print f
1 голос
/ 03 июня 2013

Упрощенная версия ответа Джохана Далина без fnmatch .

import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']
1 голос
/ 24 июня 2013

Или с пониманием списка:

 >>> base = r"c:\User\xtofl"
 >>> binfiles = [ os.path.join(base,f) 
            for base, _, files in os.walk(root) 
            for f in files if f.endswith(".jpg") ] 
1 голос
/ 23 мая 2019

Рассмотрим pathlib.rglob().

Это похоже на вызов Path.glob() с добавлением "**/" перед данным относительным шаблоном:

import pathlib


for p in pathlib.Path("src").rglob("*.c"):
    print(p)

См. Также связанную с @ taleinat запись здесь и более раннюю запись в другом месте.

0 голосов
/ 22 июня 2019

Для Python 3.5 и более поздних версий

file_names_array = glob.glob('src/*.c', recursive=True)

далее вам может понадобиться

for full_path_in_src in  file_names_array:
    print (full_path_in_src ) # be like 'abc/xyz.c'
    #Full system path of this would be like => 'path till src/abc/xyz.c'
0 голосов
/ 23 июня 2017

Мне нужно решение для python 2.x , которое работает fast в больших каталогах.
Я согласен с этим:

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

Обратите внимание, что вам может потребоваться обработка исключений в случае, если ls не найдет подходящий файл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...