Управление каталогами в 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
Ниже приведены более сложные и неочевидные сценарии использования модулей 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 удалена
Внимание: операция необратима, следует использовать с осторожностью.