Python: обход директорий и поиск нужных файлов

Раздел: Основы Python -> Файловый ввод-вывод

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

Основные подходы к поиску файлов

Как эффективно найти файл по шаблону имени, включая все вложенные папки?

Наиболее современный и рекомендуемый способ - использование объекта Path из модуля pathlib и его метода rglob. Этот метод рекурсивно обходит все подкаталоги и возвращает пути, соответствующие шаблону.


from pathlib import Path

# Создаём объект Path для корневой папки
root = Path('.')

# Ищем все файлы с расширением .txt
for file_path in root.rglob('*.txt'):
    print(file_path)

ввод программ на python (ввод данных в программе python)

Пример вывода (для папки с двумя файлами .txt):

./data/file1.txt
./docs/readme.txt

Python file io (ввод-вывод файлов в python)

Метод rglob принимает строку с шаблоном (используются правила glob: * - любая последовательность символов, ? - один символ, [abc] - один из символов). Для поиска по части имени можно использовать шаблон *запрос*.

Возможные проблемы:

  • PermissionError - возникает при отсутствии прав на чтение каталога. Решение - обернуть вызов в try-except или предварительно проверять доступность через os.access.
  • Символические ссылки - rglob по умолчанию не переходит по ссылкам (не зацикливается), но может выдавать их как файлы. Если нужно игнорировать ссылки, используйте Path.is_symlink().
  • Большие деревья - полный обход может быть медленным. Для ускорения используйте фильтрацию на лету или параллельную обработку (см. расширенные примеры).

Как найти файлы, используя старый модуль os и os.walk?

Классический метод - функция os.walk, которая рекурсивно обходит дерево каталогов. Применяется для гибкого контроля над процессом:


import os

for root_dir, dirs, files in os.walk('.'):
    for file in files:
        if file.endswith('.txt'):
            print(os.path.join(root_dir, file))

Python temp files (временные файлы в python)

Здесь root_dir - текущая папка, dirs - список подкаталогов (можно модифицировать для исключения), files - имена файлов.

Особенности: os.walk возвращает имена без указания типа (файл/папка), требуется фильтрация вручную. Проблема с символическими ссылками: по умолчанию не переходит, но если ссылка ведёт на каталог, можно попасть в цикл, изменив список dirs. Также возможна ошибка доступа - каталог пропускается автоматически.

Как найти файлы с помощью модуля glob без рекурсии?

Модуль glob предоставляет функцию glob для поиска по шаблону в одной папке. Для рекурсии используйте ** и параметр recursive=True (Python 3.5+):


import glob

# Поиск в текущей папке
for name in glob.glob('*.txt'):
    print(name)

# Рекурсивный поиск во всех подпапках
for name in glob.glob('**/*.txt', recursive=True):
    print(name)

Python index files (индексация файлов в python)

Ошибки: recursive=True работает не во всех версиях Python (требуется 3.5+). В Windows символ ** может вызывать проблемы с длинными путями. Лучше использовать pathlib для кроссплатформенности.

Как отфильтровать файлы по нескольким критериям (имя, размер, дата)?

Комбинируйте os.walk (или pathlib) с проверками через os.stat или методы Path:


from pathlib import Path
import time

root = Path('.').resolve()
# Ищем файлы больше 1 МБ, изменённые за последние 7 дней
for p in root.rglob('*'):
    if p.is_file() and p.stat().st_size > 1_000_000:
        age = time.time() - p.stat().st_mtime
        if age <= 7 * 24 * 3600:
            print(p, p.stat().st_size)

File python class (класс для работы с файлами в python)

Проблема: при большом количестве файлов повторные вызовы stat замедляют поиск. Решение - кэшировать результаты в словаре или использовать os.scandir.

Как найти файл по точному имени, не просматривая все каталоги?

Если имя известно, можно использовать pathlib и rglob с полным именем или воспользоваться os.path.exists для прямого пути. Но для поиска в неизвестной папке - только обход:


from pathlib import Path

for p in Path('.').rglob('myfile.pdf'):
    print(p)
    break  # нашли первое совпадение

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

- Python copy file (копирование файла в python)
- Python log file (логирование в файл в python)
- Python file methods (методы работы с файлами в python)

Расширенные примеры поиска файлов

Поиск файлов по размеру (больше/меньше/равно)

Пример

from pathlib import Path

root = Path('/home/user/projects')
size_limit = 100 * 1024 * 1024  # 100 MB

big_files = [f for f in root.rglob('*') if f.is_file() and f.stat().st_size > size_limit]
for f in big_files:
    print(f, f.stat().st_size)
/home/user/projects/data/bigfile.bin 104857600
/home/user/projects/backup/archive.zip 125829120

Пояснение: используется метод stat().st_size для получения размера в байтах. Для производительности можно предварительно отфильтровать по расширению, если размер важен только для определённых типов.

Поиск файлов по дате последнего изменения (за последние N дней)

Пример

from pathlib import Path
import time

root = Path('/var/log')
now = time.time()
last_7_days = now - 7 * 24 * 3600

recent_files = [f for f in root.rglob('*')
                if f.is_file() and f.stat().st_mtime > last_7_days]
for f in recent_files:
    print(f, time.ctime(f.stat().st_mtime))
/var/log/syslog Thu Apr 10 08:12:34 2025
/var/log/auth.log Thu Apr 10 09:45:12 2025

Пояснение: st_mtime - время последнего изменения файла (timestamp). Сравнивается с текущим временем минус 7 дней.

Поиск файлов по содержимому (текстовый поиск)

Пример

from pathlib import Path

root = Path('/home/user/docs')
search_term = 'Python'

for file in root.rglob('*.txt'):
    try:
        content = file.read_text(encoding='utf-8')
        if search_term in content:
            print(f'Найдено в {file}')
    except (UnicodeDecodeError, PermissionError):
        pass
Найдено в /home/user/docs/notes.txt
Найдено в /home/user/docs/tutorial.txt

Пояснение: для текстовых файлов используется read_text. Ошибки кодировки и доступа игнорируются. Для больших файлов лучше читать построчно или использовать mmap.

Рекурсивный поиск с фильтрацией по типу (папки/файлы)

Пример

from pathlib import Path

root = Path('.')

# Найти только папки (каталоги)
folders = [d for d in root.rglob('*') if d.is_dir()]
print('Папки:')
for d in folders[:5]:
    print(d)

# Найти только файлы (исключая символические ссылки)
files = [f for f in root.rglob('*') if f.is_file() and not f.is_symlink()]
print('\nФайлы (первые 5):')
for f in files[:5]:
    print(f)
Папки:
.
./data
./src
./tests
./docs

Файлы (первые 5):
./main.py
./config.json
./data/input.csv
./src/utils.py
./tests/test_main.py

Поиск файлов внутри ZIP-архива (без распаковки)

Пример

import zipfile
from pathlib import Path

archive_path = Path('archive.zip')
search_name = 'readme.txt'

with zipfile.ZipFile(archive_path, 'r') as zf:
    for info in zf.infolist():
        if search_name in info.filename:
            print(f'Найден в архиве: {info.filename}, размер: {info.file_size}')
Найден в архиве: docs/readme.txt, размер: 1024

Пояснение: модуль zipfile позволяет сканировать содержимое архива без распаковки. Для поиска по содержимому файла внутри ZIP можно использовать zf.read(info.filename).

Параллельный поиск с использованием concurrent.futures (ускорение на многоядерных системах)

Пример

from pathlib import Path
from concurrent.futures import ProcessPoolExecutor, as_completed

root = Path('/home/user')

def search_in_directory(dir_path):
    # Поиск всех .py файлов в одной директории
    return [str(p) for p in dir_path.glob('*.py')]

subdirs = [d for d in root.iterdir() if d.is_dir()]
results = []

with ProcessPoolExecutor() as executor:
    futures = {executor.submit(search_in_directory, d): d for d in subdirs}
    for future in as_completed(futures):
        results.extend(future.result())

print(f'Найдено {len(results)} .py файлов')
for r in results[:10]:
    print(r)
Найдено 42 .py файлов
/home/user/script1.py
/home/user/main.py
/home/user/module.py
...

Пояснение: разбиваем задачу по подкаталогам верхнего уровня и запускаем поиск параллельно. Эффективно при большом количестве папок. Для глубокой рекурсии можно использовать более сложное разбиение.

Поиск файла в Python - comments

En
найти файл python (python)