Обход папок и поиск файлов по маске
Чтобы обработать пачку файлов, их сначала нужно найти. 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 — ваш инструмент поиска файлов: одна папка против рекурсии, маски со звёздочкой, ленивый генератор. Не забывайте сортировать и фильтровать папки. Теперь, имея список файлов, научимся их безопасно переименовывать и раскладывать.