Как я могу искать подпапки с помощью glob.модуль glob в Python?


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

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

но это не может получить доступ к вложенных папок. Кто-нибудь знает, как я могу использовать ту же команду для доступа к подпапкам?

9 65

9 ответов:

в Python 3.5 и новее используйте новый рекурсивный **/ функции:

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

, когда recursive установлено, ** с последующим разделителем пути соответствует 0 или более подкаталогов.

в более ранних версиях Python,glob.glob() невозможно рекурсивно перечислять файлы в подкаталогах.

в таком случае я бы использовал os.walk() в сочетании с 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')]

это будет ходить ваши каталоги рекурсивно и верните все абсолютные пути к соответствию .txt файлы. В этом конкретные случае fnmatch.filter() может быть излишним, вы также можете использовать

на glob2 пакет поддерживает Дикие карты и достаточно быстро

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

на моем ноутбуке она занимает около 2 секунд, чтобы соответствовать > 60 000 путей к файлам.

для поиска файлов в непосредственных подкаталогах:

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

для рекурсивной версии, которая пересекает все подкаталоги, вы можете использовать ** и передать recursive=True начиная с Python 3.5:

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

оба вызова функции возвращают списки. Вы могли бы использовать glob.iglob() для возврата пути один за другим. Или использовать pathlib:

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

оба метода возвращают итераторы (вы можете получить пути один за другим).

можно использовать Муравьиная С Python 2.6

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

раскрытие-я являюсь автором этого пакета.

вот адаптированная версия, которая позволяет glob.glob как функциональность без использования 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

Итак, если у вас есть следующая структура dir

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

вы можете сделать что-то подобное

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

очень много fnmatch шаблон соответствует всему имени файла, а не только имени файла.

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

не работает для всех случаев, вместо этого используйте glob2

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

Если вы можете установить пакет glob2...

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

все имена файлов и папок:

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

если вы используете Python 3.4+, вы можете использовать pathlib модуль. Элемент Path.glob() метод поддерживает ** pattern, что означает "этот каталог и все подкаталоги, рекурсивно". Он возвращает генератор, дающий Path объекты для всех соответствующих файлов.

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

как указал Мартийн, Глоб может сделать это только через