Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

В 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() может быть излишним, вы также можете использовать .endswith():

import os

path = 'C:/Users/sam/Desktop/file1'

configfiles = [os.path.join(dirpath, f)
    for dirpath, dirnames, files in os.walk(path)
    for f in files if f.endswith('.txt')]

Ответ 2

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

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

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

Ответ 3

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

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

На моем ноутбуке требуется примерно 2 секунды для соответствия > 60 000 путей к файлам.

Ответ 4

Вы можете использовать Formic с Python 2.6

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

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

Ответ 5

Вот адаптированная версия, которая позволяет 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 для всего имени файла, а не только для имени файла.

Ответ 6

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

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

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

Ответ 7

Если вы можете установить пакет 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\\**\\**")  

Ответ 8

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

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

Ответ 9

Как указано Martijn, glob может делать это только через оператор **, введенный в Python 3.5. Поскольку OP явно запрашивает модуль glob, следующее возвращает ленивый итератор оценки, который ведет себя аналогично

import os, glob, itertools

configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt'))
                         for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/'))

Обратите внимание, что в этом подходе вы можете повторять только один раз над configfiles. Если вам нужен реальный список конфигурационных файлов, которые можно использовать в нескольких операциях, вам нужно будет это явно создать, используя list(configfiles).

Ответ 10

Там много путаницы по этой теме. Дайте мне посмотреть, смогу ли я уточнить это (Python 3.7):

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

Поэтому лучше всегда указывать recursive=True.