Системные вызовы и файловая система: управление путями в Python

Раздел: Python -> Взаимодействие с ОС

Работа с системными вызовами и файловыми путями в Python

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

Модуль pathlib (добавлен в Python 3.4) предоставляет объектно-ориентированный интерфейс для работы с путями файловой системы. Это рекомендуемый способ, так как код становится читаемым, кроссплатформенным и менее подвержен ошибкам.


from pathlib import Path

# Создание объекта пути
dir_path = Path('.')
file_path = Path('/tmp/example.txt')

# Основные свойства
print('Имя файла:', file_path.name)
print('Родительская директория:', file_path.parent)
print('Расширение:', file_path.suffix)
print('Путь без расширения:', file_path.stem)

# Проверка существования
if file_path.exists():
    print('Файл существует')
else:
    print('Файл не найден')

# Создание каталога (включая родительские)
new_dir = Path('/tmp/new/subdir')
new_dir.mkdir(parents=True, exist_ok=True)

# Переименование/перемещение
new_file = file_path.rename('/tmp/renamed.txt')

# Итерация по содержимому каталога
for entry in dir_path.iterdir():
    print(entry.name)

# Поиск файлов по шаблону
for py_file in dir_path.glob('*.py'):
    print('Python файл:', py_file)
    

Python run exe file (запуск exe-файла из python)

Имя файла: example.txt
Родительская директория: /tmp
Расширение: .txt
Путь без расширения: example
Файл не найден

Python send files (отправка файлов в python)

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

  • FileNotFoundError – возникает при попытке работы с несуществующим файлом. Перед операцией используйте exists().
  • PermissionError – недостаточно прав для создания/чтения файла. Проверьте права доступа.
  • Not a Directory – если путь ведёт к файлу, а не каталогу при вызове iterdir().
  • В старых версиях Python (до 3.4) модуль отсутствует. Используйте os.path как альтернативу.

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

Как работать с путями используя традиционный модуль os.path?

Модуль os.path существует с ранних версий Python и предоставляет функции для обработки строковых путей. Он полезен для поддержки старого кода или в случаях, когда pathlib нежелателен (например, при очень строгих требованиях к производительности).


import os.path

# Склеивание путей
full_path = os.path.join('/tmp', 'subdir', 'file.txt')
print('Полный путь:', full_path)

# Разделение на каталог и имя
head, tail = os.path.split(full_path)
print('Каталог:', head)
print('Имя:', tail)

# Проверка существования
if os.path.exists(full_path):
    print('Путь существует')

# Получение абсолютного пути
abs_path = os.path.abspath('.')
print('Абсолютный путь:', abs_path)
    

Python system path (системные вызовы и файловая система в python)

Полный путь: /tmp/subdir/file.txt
Каталог: /tmp/subdir
Имя: file.txt
Абсолютный путь: /home/user/project

Python py file system (работа с файловой системой в python (os, shutil))

Типичные проблемы:

  • Код менее читаем из-за множества вызовов функций внутри строк.
  • Легко ошибиться с обратными слешами на Windows – хотя os.path.join корректно обрабатывает платформу, прямое написание путей вручную часто приводит к ошибкам.
  • Отсутствие явного указания типа (путь как строка) может затруднить отладку.
  • Сложно комбинировать с другими операциями (например, с open файла).

Случаи использования: legacy-проекты, где уже используется os.path; сценарии, где нужно передавать путь как простую строку (например, в JSON).

Как добавить кастомный путь для импорта модулей через sys.path?

Список sys.path определяет, где Python ищет модули при импорте. Добавление пути в этот список позволяет загружать модули из нестандартных расположений.


import sys

# Добавление пути в начало (более высокий приоритет)
sys.path.insert(0, '/home/user/my_modules')

# Добавление в конец
sys.path.append('/home/user/extra_libs')

# Теперь можно импортировать модуль из этого пути
import my_custom_module

print(my_custom_module.__file__)  # Отобразит полный путь к модулю
    

аргументы программы python (аргументы командной строки программы на python)

/home/user/my_modules/my_custom_module.py

Python вызов программы (вызов программы из python)

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

  • Импорт может получить модуль с таким же именем из стандартной библиотеки, если путь стоит позже. Используйте insert(0,...) для приоритета.
  • Изменение sys.path глобально влияет на весь интерпретатор, что может привести к путанице в многопоточных приложениях.
  • При распространении кода изменения путей могут не работать на других машинах. Лучше использовать переменную окружения PYTHONPATH или упаковку модуля.

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

Как рекурсивно получить список всех файлов определённого расширения?

Для этого подходит комбинация os.walk или модуль glob. Первый даёт полный контроль, второй – более лаконичен.


import os
import glob

# Вариант 1: os.walk
for root, dirs, files in os.walk('/tmp'):
    for file in files:
        if file.endswith('.txt'):
            print('os.walk:', os.path.join(root, file))

# Вариант 2: glob с рекурсивным поиском (Python 3.5+)
for txt_file in glob.glob('/tmp/**/*.txt', recursive=True):
    print('glob:', txt_file)
    
os.walk: /tmp/file1.txt
os.walk: /tmp/sub/file2.txt
glob: /tmp/file1.txt
glob: /tmp/sub/file2.txt

Проблемы и ограничения:

  • os.walk может быть медленным на больших файловых системах (особенно сетевых). Используйте scandir для ускорения.
  • glob с ** требует Python 3.5+ и может не работать, если каталогов слишком много (глубина рекурсии).
  • Символические ссылки могут приводить к зацикливанию. В os.walk можно передать followlinks=False.

Случаи: поиск конфигурационных файлов, бэкапы, очистка диска.

Как выполнить системный вызов (команду) из Python и захватить вывод?

Модуль subprocess – стандартный способ выполнения внешних команд. Он заменяет устаревшие os.system и os.popen.


import subprocess

# Простой запуск команды
result = subprocess.run(['ls', '-l', '/tmp'], capture_output=True, text=True)
print('stdout:', result.stdout)

# Проверка кода возврата
if result.returncode != 0:
    print('Ошибка:', result.stderr)

# Пример с shell=True (небезопасно, используйте с осторожностью)
result_shell = subprocess.run('echo Hello World', shell=True, capture_output=True, text=True)
print('shell:', result_shell.stdout.strip())
    
stdout: total 0
-rw-r--r-- 1 user user 0 Feb 10 12:00 test.txt
...
shell: Hello World

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

  • Использование shell=True с пользовательским вводом – уязвимость для инъекций команд. Лучше передать аргументы списком.
  • Забыли указать capture_output=True – тогда вывод уйдёт в консоль, а не в переменную.
  • Команда может зависнуть, если не указан timeout. Используйте subprocess.run(..., timeout=10).

Цели: автоматизация задач администрирования, запуск внешних утилит, интеграция с системой.

Расширенные примеры работы с системными вызовами и путями

Пример

from pathlib import Path
import os
import sys
import subprocess

# 1. Работа с символическими ссылками
original = Path('/tmp/original.txt')
link = Path('/tmp/link.txt')
link.symlink_to(original)

# Проверка: является ли путь символической ссылкой
print('Is symlink:', link.is_symlink())  # True
# Получение цели ссылки
print('Target:', link.readlink())  # /tmp/original.txt

# 2. Безопасное переименование с проверкой
src = Path('/tmp/src.txt')
dst = Path('/tmp/dst.txt')
if not dst.exists():
    src.rename(dst)
else:
    print('Целевой файл уже существует, переименование пропущено')

# 3. Атомарное перемещение с помощью os.rename
# os.rename атомарна на POSIX системах (если обе файловые системы одинаковы)
os.rename('/tmp/src.txt', '/tmp/new_name.txt')

# 4. Рекурсивное изменение прав доступа
for file in Path('/tmp/project').rglob('*.py'):
    file.chmod(0o644)  # rw-r--r--

# 5. Получение метаданных файла через stat
stat_info = Path('/tmp/test.txt').stat()
print('Размер:', stat_info.st_size, 'байт')
print('Время последнего доступа:', stat_info.st_atime)
print('Режим доступа (восьмеричный):', oct(stat_info.st_mode))

# 6. Динамическое добавление пути из переменной окружения
extra_path = os.environ.get('MY_PYTHON_PATH')
if extra_path and os.path.isdir(extra_path):
    sys.path.append(extra_path)

# 7. Subprocess с захватом stderr и timeout
try:
    result = subprocess.run(
        ['ping', '-c', '4', 'example.com'],
        capture_output=True,
        text=True,
        timeout=10
    )
    print('Ping успешен' if result.returncode == 0 else 'Ping не удался')
    print('Вывод:', result.stdout)
except subprocess.TimeoutExpired:
    print('Команда превысила тайм-аут')
except subprocess.CalledProcessError as e:
    print('Ошибка выполнения:', e.stderr)

# 8. Использование tempfile для временных файлов
from tempfile import NamedTemporaryFile
with NamedTemporaryFile(mode='w', suffix='.txt', delete=True) as tmp:
    tmp.write('Это временный файл')
    tmp_path = tmp.name
    print('Создан временный файл:', tmp_path)

# 9. Работа с путями в Windows и Unix (кроссплатформенность)
from pathlib import PurePosixPath, PureWindowsPath
unix_path = PurePosixPath('/home/user/file.txt')
win_path = PureWindowsPath('C:\\Users\\user\\file.txt')
print('Unix:', unix_path)
print('Windows:', win_path)

# Конвертация в нативный путь (на текущей ОС)
native = Path('/tmp/file.txt')
print('Нативный:', native)
Is symlink: True
Target: /tmp/original.txt
Целевой файл уже существует, переименование пропущено
Размер: 1234 байт
Время последнего доступа: 1700000000.123
Режим доступа (восьмеричный): 0o100644
Создан временный файл: /tmp/tmpabc123.txt
Unix: /home/user/file.txt
Windows: C:\Users\user\file.txt
Нативный: /tmp/file.txt
Ping успешен
Вывод: PING example.com (93.184.216.34) ...

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

Системные вызовы и файловая система в Python - comments

En
Python system path (python)