Обход папок и поиск файлов по маске

Чтобы обработать пачку файлов, их сначала нужно найти. pathlib умеет обходить папки и отбирать файлы по шаблону имени — это первый шаг любой пакетной задачи.
Суть: glob('*.csv') ищет в одной папке, rglob('*.csv') — рекурсивно во всех подпапках. Звёздочка — это «любые символы».

Типичная задача: «обработай все Excel-файлы в папке отчётов». Чтобы её решить, нужно получить список этих файлов. В pathlib для этого есть два метода. glob(pattern) ищет совпадения в одной папке, а rglob(pattern) (recursive glob) спускается во все вложенные папки. Шаблон использует подстановочные символы: * — любая последовательность, ? — один символ.

СТРУКТУРА ПАПОК И ПОИСК

  reports/
  +-- 2025/
  |   +-- jan.csv
  |   +-- feb.csv
  +-- 2026/
  |   +-- mar.csv
  +-- notes.txt

  glob('*.csv')   -> (ничего, csv лежат глубже)
  rglob('*.csv')  -> jan.csv, feb.csv, mar.csv

В браузере у нас нет реальной файловой системы, но логику фильтрации по маске и расширению можно полностью отработать на списке имён — именно так работает glob внутри. Разберём фильтрацию вручную.

Попробуй сам ▶

import fnmatch

# Имитируем содержимое папки (так glob получает имена от ОС)
files = ['jan.csv', 'feb.csv', 'notes.txt',
         'report_2026.xlsx', 'mar.CSV', 'draft.csv.bak']

# fnmatch — тот же движок масок, что и в glob
csv_files = [f for f in files if fnmatch.fnmatch(f.lower(), '*.csv')]
print('CSV-файлы:', csv_files)

# Точная проверка расширения надёжнее маски:
exact = [f for f in files if f.lower().endswith('.csv')]
print('Строго .csv:', exact)
# Заметь: draft.csv.bak не попал — расширение .bak

Обратите внимание на draft.csv.bak: маска *.csv его не берёт, потому что расширение — .bak. Это важная тонкость: *.csv в glob проверяет именно конец имени, а не наличие подстроки.

В реальном коде на pathlib то же самое выглядит так — этот фрагмент обращается к диску, поэтому он показан как нерабочая в браузере врезка.

from pathlib import Path

folder = Path('reports')
for csv in sorted(folder.rglob('*.csv')):
    print(csv.name, '->', csv.stat().st_size, 'байт')

# Только файлы, без папок:
files = [p for p in folder.rglob('*') if p.is_file()]

На практике поиск файлов почти всегда — первый шаг более крупной задачи, и его удобно отделять от обработки. Сначала вы собираете и сортируете список целевых файлов, при желании печатаете его для проверки, и только потом запускаете обработку в цикле. Такое разделение даёт сразу две выгоды: во-первых, вы видите, что именно скрипт собирается трогать, ещё до того как он начнёт что-то менять; во-вторых, список легко ограничить (например, взять первые три файла) для безопасного теста. Привычка «сначала найти и показать, потом обрабатывать» спасает от случайной порчи лишних файлов.

Как работает под капотом

glob возвращает генератор, а не список: файлы выдаются по одному, по мере обхода каталога. Это экономит память на огромных папках — не нужно держать в памяти миллион путей сразу. Если вам нужен список, оберните результат в list() или sorted().

Под капотом маска компилируется в регулярное выражение, а обход каталога делается системным вызовом ОС, который возвращает имена в произвольном порядке. Поэтому, если порядок важен (а для отчётов он почти всегда важен), результат нужно явно сортировать через sorted().

Частые ошибки

  • Полагаться на порядок файлов. ОС не гарантирует сортировку. Всегда оборачивайте в sorted().
  • Забывать про регистр. На Linux *.csv не найдёт FILE.CSV. Приводите к нижнему регистру или используйте обе маски.
  • Брать папки как файлы. rglob('*') вернёт и каталоги. Фильтруйте через .is_file().

Best practices

  • Сначала соберите и отсортируйте список файлов, потом обрабатывайте — так проще логировать и отлаживать.
  • Для надёжной проверки расширения используйте suffix.lower(), а не маску.
  • На больших папках работайте с генератором лениво, не материализуя весь список.

Итоги. glob и rglob — ваш инструмент поиска файлов: одна папка против рекурсии, маски со звёздочкой, ленивый генератор. Не забывайте сортировать и фильтровать папки. Теперь, имея список файлов, научимся их безопасно переименовывать и раскладывать.

Проверьте себя
1. Чем rglob отличается от glob?
Arglob ищет только в текущей папке
Brglob ищет рекурсивно во всех подпапках
Crglob возвращает только папки
DМежду ними нет разницы
2. Почему результат glob часто оборачивают в sorted()?
AИначе glob вернёт ошибку
BОС не гарантирует порядок файлов, а для отчётов он важен
Csorted ускоряет обход диска
DБез sorted glob вернёт дубликаты