Управление каталогами в Python: все способы и примеры

Раздел: Ввод-вывод -> Файловый ввод-вывод

Работа с директориями файлов в Python

Как эффективно и безопасно работать с директориями в современном Python?

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


from pathlib import Path

# Создание объекта пути к директории
dir_path = Path('/home/user/documents')
# Проверка существования
if dir_path.exists():
    print(f'Директория {dir_path} существует')
# Создание новой директории (включая родительские, если нужно)
dir_path.mkdir(parents=True, exist_ok=True)
# Получение списка содержимого
for item in dir_path.iterdir():
    print(item.name)
  

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

Пояснение:

  • Path() создаёт объект, представляющий путь.
  • exists() проверяет, существует ли директория.
  • mkdir(parents=True, exist_ok=True) создаёт директорию, не вызывая ошибку, если она уже есть.
  • iterdir() возвращает генератор всех элементов внутри директории.

Типичные ошибки:

  • Ошибка FileNotFoundError при попытке открыть файл из несуществующей директории - решается предварительной проверкой exists() или созданием через mkdir().
  • Ошибка PermissionError при недостатке прав - обрабатывать через try/except.
  • Пути с обратной косой чертой (\ на Windows) - pathlib автоматически адаптирует разделители, но если передать строку вручную, лучше использовать Path(r'C:\Users\...') или '/'.join().

Как проверить, является ли объект директорией, с помощью модуля os.path?

Классический способ, подходящий для кода, поддерживающего Python 2.x или уже использующего модуль os. Функция os.path.isdir() возвращает True, если путь указывает на существующую директорию.


import os.path

dir_path = '/tmp/my_folder'
if os.path.isdir(dir_path):
    print('Это директория')
else:
    print('Такого пути нет или это файл')
  

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

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

Как получить список всех файлов и папок в директории, не используя pathlib?

Функция os.listdir() возвращает список имён всех элементов в указанной директории. Для получения полных путей удобно комбинировать с os.path.join().


import os

dir_path = '/tmp'
items = os.listdir(dir_path)
for name in items:
    full_path = os.path.join(dir_path, name)
    if os.path.isdir(full_path):
        print(f'{name} - папка')
    else:
        print(f'{name} - файл')
  

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

Недостаток: os.listdir() возвращает только имена, не различает файлы и папки (требуется дополнительная проверка). Также не рекурсивен.

Как эффективно обойти содержимое большой директории с помощью os.scandir?

Функция os.scandir() возвращает итератор объектов DirEntry, каждый из которых содержит имя и информацию о типе (файл/папка) без дополнительных системных вызовов. Это быстрее, чем os.listdir() с последующими проверками.


import os

with os.scandir('/tmp') as entries:
    for entry in entries:
        if entry.is_dir():
            print(f'Папка: {entry.name}')
        else:
            print(f'Файл: {entry.name}')
  

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

Проблемы:

  • При использовании os.scandir() с итератором важно вызывать entry.stat() только когда это необходимо, чтобы не получить задержку.
  • Закрытие итератора через with или явный вызов .close() - иначе ресурсы могут не освободиться на Windows.

Как найти файлы по шаблону (glob) в директории и её поддиректориях?

Модуль glob предоставляет функции для поиска путей, соответствующих заданному шаблону (с символами *, ?, []). glob.glob() возвращает список строк, glob.iglob() - итератор.


import glob

# Найти все .txt файлы непосредственно в /tmp
for path in glob.glob('/tmp/*.txt'):
    print(path)

# Рекурсивный поиск во всех поддиректориях (Python 3.5+)
for path in glob.glob('/tmp/**/*.txt', recursive=True):
    print(path)
  

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

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

Как рекурсивно обойти все поддиректории для выполнения действий над каждым файлом?

Функция os.walk() генерирует кортежи (путь к текущей папке, список подпапок, список файлов) для каждой директории, начиная с указанной. Позволяет выполнять произвольные действия.


import os

for root, dirs, files in os.walk('/tmp'):
    for file in files:
        full_path = os.path.join(root, file)
        print(full_path)
  

Python file utf 8 (кодировка utf-8 для файлов в python)

Подходит для операций, требующих обхода всего дерева (удаление, копирование, подсчёт).

Как создать временную директорию для временных файлов?

Модуль tempfile предоставляет функцию tempfile.mkdtemp(), которая создаёт уникальную временную папку и возвращает её путь.


import tempfile

with tempfile.TemporaryDirectory() as tmpdir:
    print(f'Временная директория: {tmpdir}')
    # Работа с файлами внутри tmpdir...
    # после выхода из блока with директория автоматически удаляется
  

Типичные ошибки:

  • Забыть закрыть контекстный менеджер - временная папка останется (если используется mkdtemp() без TemporaryDirectory).
  • При ручном удалении временных папок возможны ошибки, если файлы внутри заняты другим процессом.
- Python log file (логирование в файл в python)
- Python file methods (методы работы с файлами в python)
- File models in python (модели файлов в python)

Расширенные примеры работы с директориями в Python

Ниже приведены более сложные и неочевидные сценарии использования модулей pathlib, os, shutil и других.

Пример 1. Рекурсивное копирование всей структуры директорий с фильтрацией по расширению

Пример

import shutil
from pathlib import Path

def copy_filtered(src_base: Path, dst_base: Path, extensions: set):
    for src_path in src_base.rglob('*'):
        if src_path.is_file() and src_path.suffix in extensions:
            # Формируем относительный путь
            rel_path = src_path.relative_to(src_base)
            dst_path = dst_base / rel_path
            dst_path.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy2(src_path, dst_path)

src = Path('/data/source')
dst = Path('/data/backup')
copy_filtered(src, dst, {'.jpg', '.png'})
# Результат: в /data/backup будут скопированы только .jpg и .png файлы с сохранением структуры папок

Пояснение: rglob('*') рекурсивно обходит все файлы и папки. relative_to() получает путь относительно исходной базы. shutil.copy2() копирует файл с метаданными.

Пример 2. Получение размера директории (суммарного объёма всех файлов) с помощью pathlib

Пример

from pathlib import Path

def get_dir_size(path: Path) -> int:
    total = 0
    for entry in path.rglob('*'):
        if entry.is_file():
            total += entry.stat().st_size
    return total

dir_path = Path('/var/log')
size_bytes = get_dir_size(dir_path)
print(f'Размер директории: {size_bytes} байт ({size_bytes / (1024**2):.2f} МБ)')
# Размер директории: 1048576 байт (1.00 МБ)

Пояснение: используется rglob('*') для обхода, stat().st_size возвращает размер файла. Внимание: при большом количестве файлов может быть медленно; альтернатива - os.walk() с os.path.getsize().

Пример 3. Синхронизация двух директорий с сохранением времени модификации

Пример

import hashlib
from pathlib import Path
import shutil

def file_hash(path: Path, chunk_size=8192) -> str:
    h = hashlib.sha256()
    with open(path, 'rb') as f:
        for chunk in iter(lambda: f.read(chunk_size), b''):
            h.update(chunk)
    return h.hexdigest()

def sync_dirs(src: Path, dst: Path):
    if not dst.exists():
        dst.mkdir(parents=True)
    for src_path in src.rglob('*'):
        rel = src_path.relative_to(src)
        dst_path = dst / rel
        if src_path.is_dir():
            dst_path.mkdir(exist_ok=True)
        else:
            if not dst_path.exists() or file_hash(src_path) != file_hash(dst_path):
                shutil.copy2(src_path, dst_path)
                print(f'Обновлён: {dst_path}')

sync_dirs(Path('/data/orig'), Path('/data/backup'))
# Обновлён: /data/backup/sub/file.txt
# Обновлён: /data/backup/readme.md

Пояснение: проверка хеша гарантирует, что копируется только изменённое содержимое. shutil.copy2 сохраняет время модификации.

Пример 4. Использование os.scandir для быстрого подсчёта количества файлов и папок

Пример

import os

def count_entries(path: str) -> dict:
    files = 0
    dirs = 0
    with os.scandir(path) as it:
        for entry in it:
            if entry.is_dir():
                dirs += 1
            else:
                files += 1
    return {'files': files, 'dirs': dirs}

result = count_entries('/usr/lib')
print(result)
# {'files': 342, 'dirs': 15}

Пример демонстрирует эффективность os.scandir - один системный вызов на запись.

Пример 5. Генератор путей с фильтром по дате изменения (pathlib)

Пример

from pathlib import Path
import time

def files_newer_than(path: Path, cutoff_timestamp: float):
    for f in path.rglob('*'):
        if f.is_file() and f.stat().st_mtime > cutoff_timestamp:
            yield f

cutoff = time.time() - 86400  # 24 часа назад
dir_path = Path('/home/user')
for recent_file in files_newer_than(dir_path, cutoff):
    print(recent_file)
# /home/user/notes.txt
# /home/user/pictures/screenshot.png

Используется для поиска недавно изменённых файлов.

Пример 6. Создание глубокой иерархии директорий с одним вызовом mkdir

Пример

from pathlib import Path

# Создать папки project/data/images, если не существуют
Path('project/data/images').mkdir(parents=True, exist_ok=True)
# Проверка:
print(Path('project/data/images').exists())  # True
# True

Пояснение: parents=True создаёт все промежуточные недостающие папки. exist_ok=True предотвращает ошибку, если папка уже существует.

Пример 7. Рекурсивное удаление директории с использованием shutil.rmtree

Пример

import shutil
from pathlib import Path

dir_to_remove = Path('/tmp/old_project')
if dir_to_remove.exists():
    shutil.rmtree(dir_to_remove)
    print(f'Директория {dir_to_remove} удалена')
else:
    print('Директория не существует')
# Директория /tmp/old_project удалена

Внимание: операция необратима, следует использовать с осторожностью.

Директория файла в Python - comments

En
Python file directory (python)