Glob в Python: как искать файлы по шаблонам и автоматизировать работу

Пройдите тест, узнайте какой профессии подходите
Сколько вам лет
0%
До 18
От 18 до 24
От 25 до 34
От 35 до 44
От 45 до 49
От 50 до 54
Больше 55

Для кого эта статья:

  • Python-разработчики, как начинающие, так и более опытные
  • Студенты и обучающиеся в области программирования
  • Профессионалы, занимающиеся автоматизацией задач и обработкой данных

    Каждый Python-разработчик рано или поздно сталкивается с необходимостью найти множество файлов определенного типа. Например, собрать все CSV с данными для анализа, обработать пакетно все изображения в папке или найти все Python-скрипты в проекте. Вручную перебирать сотни файлов — путь в никуда. Здесь на сцену выходит модуль glob — элегантный инструмент стандартной библиотеки Python, который решает задачу поиска файлов по шаблонам буквально в одну строку кода. 🔍 Мастерство использования glob отличает профессионального разработчика от новичка.

Хотите уверенно работать с файловой системой и автоматизировать рутинные задачи? Обучение Python-разработке от Skypro включает глубокое изучение работы с файловой системой, включая продвинутые техники использования модуля glob. Вы не только освоите теорию, но и примените знания в реальных проектах под руководством опытных менторов. Превратите хаос файлов в организованную систему уже через несколько недель практики!

Что такое модуль glob и зачем он нужен в Python

Модуль glob — это часть стандартной библиотеки Python, предназначенная для поиска файлов, соответствующих заданному шаблону. Его название происходит от термина "global pattern matching" (глобальное сопоставление с шаблоном), что точно описывает его функциональность. В основе glob лежит концепция Unix-подобных шаблонов, знакомая пользователям командной строки.

Отличие glob от обычного перебора файлов через os.listdir() заключается в возможности использовать специальные символы-шаблоны:

  • * — соответствует любой последовательности символов
  • ? — соответствует любому одиночному символу
  • [seq] — соответствует любому символу из последовательности
  • [!seq] — соответствует любому символу, не входящему в последовательность

Но зачем вообще нужен glob, если существуют методы os.walk() и os.listdir()? Преимущество glob — в лаконичности и выразительности. Сравните две реализации одной задачи:

Поиск с использованием os Поиск с использованием glob
python<br>import
Скопировать код

|

python<br>import
Скопировать код

|

Очевидно, что второй вариант значительно компактнее и читабельнее. Glob — это инструмент, который делает код более декларативным: вы описываете, что хотите найти, а не как это сделать. 🧩

Алексей Воронов, Python-разработчик Я работал над проектом автоматизации отчётности, где требовалось ежедневно обрабатывать сотни CSV-файлов из разных департаментов. Названия файлов следовали формату "департаментдататип.csv", и каждый департамент имел свою специфику именования.

Первоначально я написал сложную функцию на 30+ строк с множеством условий и проверок имён файлов через регулярные выражения. Код работал, но был хрупким и трудно поддерживаемым.

Когда я открыл для себя модуль glob, всё изменилось. Задача поиска всех файлов определённого департамента за конкретную дату сократилась до:

Python
Скопировать код
files = glob.glob(f'data/{department}_*_{date}*.csv')

А для обработки файлов по всем департаментам за месяц:

Python
Скопировать код
files = glob.glob(f'data/*_2023-06-*.csv')

Код стал настолько понятным, что даже менеджеры без технического образования могли посмотреть на него и понять, что происходит. Время обработки сократилось, а количество потенциальных ошибок уменьшилось до нуля.

Пошаговый план для смены профессии

Основы использования glob.glob() для поиска файлов

Функция glob.glob() — основной инструмент модуля, возвращающий список путей к файлам, соответствующих заданному шаблону. Её использование интуитивно понятно даже начинающим программистам:

Python
Скопировать код
import glob

# Найти все Python-файлы в текущем каталоге
python_files = glob.glob('*.py')

# Найти все изображения
images = glob.glob('*.jpg') + glob.glob('*.png') + glob.glob('*.gif')

# Найти файлы с определенным префиксом
log_files = glob.glob('app_log_*.txt')

print(python_files) # ['script.py', 'utils.py', 'main.py', ...]

Важный момент: glob.glob() возвращает абсолютные пути, если шаблон начинается с корня файловой системы, и относительные пути в противном случае. Это поведение необходимо учитывать при дальнейшей обработке результатов.

Шаблоны можно комбинировать, создавая более сложные условия поиска:

  • 'data/*/*.csv' — найдёт CSV-файлы во всех подкаталогах каталога 'data'
  • '**/test_*.py' — найдёт все тестовые Python-файлы в любом каталоге (с Python 3.5+)
  • 'docs/[0-9]*.txt' — найдёт текстовые файлы в каталоге 'docs', имена которых начинаются с цифры

Порядок выполнения поиска имеет значение: glob не сортирует результаты автоматически. Если вам нужен отсортированный список, используйте стандартную функцию sorted():

Python
Скопировать код
# Получить отсортированный список файлов
sorted_files = sorted(glob.glob('*.txt'))

Результаты функции glob.glob() можно сразу использовать в циклах для обработки найденных файлов — это типичный сценарий применения:

Python
Скопировать код
# Обработка всех CSV-файлов
for csv_file in glob.glob('data/*.csv'):
with open(csv_file, 'r') as f:
# Обработка содержимого файла
data = f.read()
print(f"Обрабатывается {csv_file}, размер: {len(data)} байт")

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

Продвинутый синтаксис шаблонов в модуле glob Python

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

Шаблон Описание Пример
* Соответствует любой последовательности символов (кроме разделителей пути) *.txt — все текстовые файлы
? Соответствует любому одиночному символу file?.txt — file1.txt, fileA.txt, но не file10.txt
[abc] Соответствует любому символу из указанных в скобках file[123].txt — file1.txt, file2.txt, file3.txt
[a-z] Соответствует любому символу из диапазона file[a-c].txt — filea.txt, fileb.txt, filec.txt
[!abc] Соответствует любому символу, кроме указанных file[!123].txt — fileA.txt, file4.txt, но не file1.txt
** Рекурсивно соответствует всем каталогам (Python 3.5+) **/*.py — все Python-файлы в любом подкаталоге

Рассмотрим несколько интересных примеров использования сложных шаблонов:

Python
Скопировать код
# Файлы, имена которых содержат 3 цифры подряд
files_with_digits = glob.glob('*[0-9][0-9][0-9]*.*')

# Файлы с именами, начинающимися на гласные буквы
vowel_files = glob.glob('[aeiouAEIOU]*.*')

# Файлы с определенными расширениями (документы)
docs = glob.glob('*.[pd][do][cf]*') # Найдёт .pdf, .doc, .docx и т.д.

# Исключение определённых файлов
non_backup_files = glob.glob('*.[!b][!a][!k]') # Исключает файлы .bak

Комбинируя различные шаблоны, можно создавать чрезвычайно гибкие условия поиска. Например, найти все файлы журналов за определённый месяц:

Python
Скопировать код
# Поиск логов за май 2023 года (формат имени: log_YYYY-MM-DD.log)
may_logs = glob.glob('log_2023-05-??.log')

Один из малоизвестных, но мощных приёмов — использование альтернативных шаблонов с помощью фигурных скобок. Это не стандартная функциональность glob, но она доступна в некоторых реализациях UNIX, и её можно эмулировать в Python:

Python
Скопировать код
# Эмуляция альтернативных шаблонов через несколько вызовов glob
image_files = []
for ext in ['jpg', 'jpeg', 'png', 'gif']:
image_files.extend(glob.glob(f'*.{ext}'))

# Тот же результат с использованием генератора списков
image_files = [f for ext in ['jpg', 'jpeg', 'png', 'gif'] for f in glob.glob(f'*.{ext}')]

Помните, что шаблоны glob чувствительны к регистру в операционных системах с чувствительной к регистру файловой системой (Unix, Linux). В Windows glob обычно не чувствителен к регистру, что соответствует поведению самой файловой системы. ⚠️

Рекурсивный поиск и glob.iglob() для больших каталогов

Работа с большими каталогами ставит перед разработчиками две основные проблемы: как организовать рекурсивный поиск и как избежать переполнения памяти. Python 3.5+ решает первую проблему с помощью параметра recursive=True, а вторую — с помощью функции glob.iglob().

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

Python
Скопировать код
import glob

# Рекурсивный поиск всех Python-файлов
all_python_files = glob.glob('**/*.py', recursive=True)

# Рекурсивный поиск по нескольким критериям
all_data_files = glob.glob('**/*.csv', recursive=True) + glob.glob('**/*.xlsx', recursive=True)

print(f"Найдено {len(all_python_files)} Python файлов")

Для больших каталогов с тысячами файлов функция glob.glob() может потреблять слишком много памяти, так как она сразу возвращает полный список всех найденных файлов. Здесь на помощь приходит glob.iglob() — итератор, который генерирует найденные пути "на лету", один за другим, что значительно снижает потребление памяти:

Python
Скопировать код
# Память-эффективная обработка большого количества файлов
for python_file in glob.iglob('**/*.py', recursive=True):
with open(python_file, 'r') as f:
# Обработка файла без хранения всех путей в памяти
content = f.read()
if 'TODO' in content:
print(f"TODO найдено в {python_file}")

Преимущества glob.iglob() особенно заметны при обработке больших объемов данных, где полный список файлов может потенциально не поместиться в оперативную память. Рассмотрим более сложный пример с использованием генератора для экономии памяти:

Python
Скопировать код
def process_large_files():
# Создаем генератор для обработки больших файлов по одному
large_files = (
file for file in glob.iglob('**/*.csv', recursive=True)
if os.path.getsize(file) > 1024 * 1024 # Файлы больше 1 МБ
)

# Обрабатываем каждый файл по очереди
for file_path in large_files:
print(f"Обработка большого файла: {file_path}")
# Здесь код обработки файла

При работе с большими каталогами важно учитывать производительность. Вот несколько практических рекомендаций:

  • Используйте более конкретные шаблоны, чтобы уменьшить количество проверяемых файлов
  • Применяйте glob.iglob() вместо glob.glob() для больших наборов данных
  • Ограничивайте глубину рекурсии там, где это возможно, используя более конкретные пути
  • Предварительно фильтруйте каталоги, если знаете, где искать

Сравнение потребления памяти при использовании различных методов для обработки 10,000 файлов:

Мария Соколова, тренер по Python Однажды мне пришлось автоматизировать процесс обработки фотоархива, содержащего более 500,000 изображений. Моему студенту потребовалось найти все фотографии, сделанные в определенные годы и с определенными параметрами камеры (извлекаемыми из EXIF-данных).

Сначала он попытался использовать стандартный подход с glob.glob():

Python
Скопировать код
all_images = glob.glob('Photos/**/*.jpg', recursive=True)
# Затем фильтрация по EXIF

Этот код аварийно завершился с ошибкой нехватки памяти, так как пытался загрузить в память полмиллиона путей к файлам одновременно.

Мы переписали код с использованием iglob():

Python
Скопировать код
for image_path in glob.iglob('Photos/**/*.jpg', recursive=True):
# Обработка каждого изображения по очереди
exif_data = get_exif(image_path)
if matches_criteria(exif_data):
process_image(image_path)

Код заработал, но обработка шла медленно — примерно 24 часа на весь архив.

Следующий шаг был критически важным. Мы заметили, что фотографии организованы по годам и месяцам в структуре Photos/YYYY/MM/. Зная, что нужны только снимки 2018-2020 годов, мы оптимизировали шаблон:

Python
Скопировать код
patterns = [f'Photos/20{year}/**/*.jpg' for year in range(18, 21)]
for pattern in patterns:
for image_path in glob.iglob(pattern, recursive=True):
# Более целенаправленная обработка

Это сократило время обработки до 3 часов. Опыт показал, насколько важно не только знать инструменты Python, но и понимать, как их эффективно применять в контексте конкретной задачи.

Практические задачи: автоматизация работы с файлами

Модуль glob раскрывает свой потенциал в реальных задачах автоматизации. Рассмотрим несколько практических сценариев, где glob становится незаменимым инструментом. 🛠️

1. Пакетная обработка файлов определённого типа

Python
Скопировать код
import glob
import pandas as pd
import os

# Объединение нескольких CSV-файлов в один DataFrame
def merge_csv_files(directory):
all_data = []
for csv_file in glob.glob(f'{directory}/*.csv'):
df = pd.read_csv(csv_file)
df['source_file'] = os.path.basename(csv_file) # Добавляем информацию об источнике
all_data.append(df)

if all_data:
return pd.concat(all_data, ignore_index=True)
return pd.DataFrame()

# Использование функции
combined_data = merge_csv_files('data/sales')
print(f"Объединено {len(combined_data)} строк из разных CSV-файлов")

2. Очистка временных файлов

Python
Скопировать код
import glob
import os
import time

def cleanup_temp_files(directory, days_old=7):
"""Удаляет временные файлы старше указанного количества дней"""
current_time = time.time()
deleted_count = 0

# Ищем все временные файлы
temp_patterns = [f'{directory}/**/*.tmp', f'{directory}/**/*.temp', f'{directory}/**/~*']

for pattern in temp_patterns:
for temp_file in glob.glob(pattern, recursive=True):
# Проверяем возраст файла
file_age_days = (current_time – os.path.getmtime(temp_file)) / (60*60*24)
if file_age_days > days_old:
try:
os.remove(temp_file)
deleted_count += 1
print(f"Удалён: {temp_file}")
except Exception as e:
print(f"Ошибка при удалении {temp_file}: {e}")

return deleted_count

# Использование
removed = cleanup_temp_files('/path/to/project')
print(f"Удалено {removed} временных файлов")

3. Автоматическая организация файлов по типам

Python
Скопировать код
import glob
import os
import shutil

def organize_files_by_type(source_dir):
"""Организует файлы в подкаталоги по их типу"""
# Словарь соответствия расширений и папок
extensions_map = {
'documents': ['doc', 'docx', 'pdf', 'txt', 'rtf'],
'images': ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff'],
'audio': ['mp3', 'wav', 'ogg', 'flac'],
'video': ['mp4', 'avi', 'mkv', 'mov', 'wmv'],
'code': ['py', 'js', 'html', 'css', 'java', 'cpp']
}

# Создаем каталоги, если они не существуют
for folder in extensions_map:
os.makedirs(os.path.join(source_dir, folder), exist_ok=True)

# Перемещаем файлы
moved_files = 0

for file_path in glob.glob(f'{source_dir}/*.*'):
# Пропускаем каталоги
if os.path.isdir(file_path):
continue

# Получаем расширение файла без точки
ext = os.path.splitext(file_path)[1][1:].lower()

# Определяем, в какую папку переместить файл
target_folder = None
for folder, extensions in extensions_map.items():
if ext in extensions:
target_folder = folder
break

if target_folder:
filename = os.path.basename(file_path)
destination = os.path.join(source_dir, target_folder, filename)

# Проверяем, существует ли файл с таким именем
if os.path.exists(destination):
name, ext = os.path.splitext(filename)
destination = os.path.join(source_dir, target_folder, f"{name}_copy{ext}")

shutil.move(file_path, destination)
moved_files += 1

return moved_files

# Использование
count = organize_files_by_type('/path/to/downloads')
print(f"Организовано {count} файлов")

4. Мониторинг изменений в каталоге

Создадим простую систему мониторинга, которая отслеживает появление новых файлов определенного типа и выполняет действия с ними:

Python
Скопировать код
import glob
import time
import os
import hashlib

def monitor_directory(directory, pattern, interval=60):
"""Мониторит директорию на появление новых файлов, соответствующих шаблону"""
known_files = {}

print(f"Начало мониторинга {directory} для файлов {pattern}")
print(f"Проверка каждые {interval} секунд")

try:
while True:
current_files = {}

# Сканируем файлы, соответствующие шаблону
for file_path in glob.glob(os.path.join(directory, pattern)):
# Вычисляем хеш файла для отслеживания изменений
with open(file_path, 'rb') as f:
file_hash = hashlib.md5(f.read()).hexdigest()

current_files[file_path] = file_hash

# Проверяем новые файлы
for file_path, file_hash in current_files.items():
if file_path not in known_files:
print(f"Обнаружен новый файл: {file_path}")
process_new_file(file_path) # Обработка нового файла
elif known_files[file_path] != file_hash:
print(f"Файл изменен: {file_path}")
process_changed_file(file_path) # Обработка измененного файла

# Проверяем удаленные файлы
for file_path in list(known_files.keys()):
if file_path not in current_files:
print(f"Файл удален: {file_path}")

# Обновляем список известных файлов
known_files = current_files

# Пауза перед следующей проверкой
time.sleep(interval)

except KeyboardInterrupt:
print("Мониторинг остановлен")

def process_new_file(file_path):
"""Обрабатывает новый файл"""
print(f"Обработка нового файла: {file_path}")
# Здесь код обработки нового файла

def process_changed_file(file_path):
"""Обрабатывает измененный файл"""
print(f"Обработка измененного файла: {file_path}")
# Здесь код обработки измененного файла

# Использование
# monitor_directory('/path/to/watch', '*.pdf', 30) # Проверка каждые 30 секунд

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

Грамотное использование модуля glob значительно упрощает работу с файловой системой в Python. Благодаря его лаконичному синтаксису и гибким возможностям поиска по шаблонам, вы можете писать более элегантный и поддерживаемый код. Масштабируйте свои решения от простого поиска файлов до сложных систем автоматизации, используя рекурсивный поиск для глубоких каталогов и итераторы для эффективной работы с большими объемами данных. Модуль glob превращает сложные задачи управления файлами в изящные однострочники, экономя ваше время и усилия. Пишите меньше кода, делайте больше работы — вот истинная философия Python в действии.

Загрузка...