Взаимодействие Python с системой через модуль os

Раздел: Python -> Системные библиотеки

Основные возможности библиотеки os

Наиболее эффективное решение: работа с путями через os.path

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

import os

# Правильное объединение пути
folder = "data"
file = "report.txt"
full_path = os.path.join(folder, file)
print(full_path)  # data/report.txt на Unix, data\report.txt на Windows

# Разделение пути на части
dir_name, base_name = os.path.split(full_path)
print(dir_name)   # data
print(base_name)  # report.txt

# Получение расширения
name, ext = os.path.splitext(base_name)
print(name)  # report
print(ext)   # .txt

библиотека os python (библиотека os для python)

Ошибки часто возникают при попытке передать абсолютный путь с обратной косой чертой на Unix или при использовании конкатенации строк. Рекомендуется всегда использовать os.path.join.

Проблема: если один из компонентов пути содержит разделитель, os.path.join начинает с него. Поэтому не стоит объединять абсолютные и относительные пути без проверки.

print(os.path.join('/home', '/data'))  # /data (игнорируется первый компонент)

библиотека sys python (библиотека sys в python)

Для проверки существования пути и его типа применяют os.path.exists, os.path.isfile, os.path.isdir:

path = "/tmp/test"
if os.path.exists(path):
    if os.path.isfile(path):
        print("Это файл")
    elif os.path.isdir(path):
        print("Это директория")
else:
    print("Путь не существует")

Такой подход универсален для любой ОС и является базой для работы с файловой системой.

Как получить текущую рабочую директорию?

Функция os.getcwd() возвращает абсолютный путь к текущей рабочей папке. Изменить её можно с помощью os.chdir(path).

import os

current = os.getcwd()
print("Сейчас работаем в:", current)

os.chdir("/tmp")
print("Перешли в", os.getcwd())

Ошибка: если указанная директория не существует или нет прав доступа, chdir вызовет FileNotFoundError или PermissionError.

Как создать несколько вложенных директорий за один вызов?

os.makedirs(dir, exist_ok=False) создаёт все промежуточные папки. Если exist_ok=True, ошибка при существовании конечной директории не возникнет.

import os

path = "project/data/2025"
os.makedirs(path, exist_ok=True)
print("Директория", path, "создана или уже существует")

Типичная ошибка: вызов os.mkdir для вложенной структуры - он создаёт только один уровень. Если родительская папка отсутствует, возникает FileNotFoundError.

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

os.walk(top) возвращает генератор кортежей (dirpath, dirnames, filenames) для каждого подкаталога.

import os

root = "/tmp/mydata"
for dirpath, dirnames, filenames in os.walk(root):
    print("Текущая папка:", dirpath)
    for f in filenames:
        if f.endswith(".py"):
            full = os.path.join(dirpath, f)
            print("  Найден .py файл:", full)

Важно: os.walk следует по символическим ссылкам на директории, что может привести к зацикливанию. Чтобы избежать этого, используйте параметр followlinks=False.

Как получить переменные окружения?

Словарь os.environ содержит все переменные окружения. Доступ к конкретной - os.environ.get('VAR'). Изменение - os.environ['VAR']='value', но это влияет только на текущий процесс.

import os

home = os.environ.get('HOME', '/tmp')
print("Домашняя папка:", home)

# Добавление новой переменной
os.environ['MY_VAR'] = 'test'
print(os.environ['MY_VAR'])

Ошибка: попытка обратиться к несуществующей переменной через os.environ['KEY'] вызывает KeyError. Используйте .get() с значением по умолчанию.

Как выполнить системную команду?

os.system(command) запускает команду в подпроцессе и возвращает код возврата. Для более гибкого управления рекомендуется subprocess, но в простых случаях os.system удобен.

import os

ret = os.system('ls -la')
print("Код возврата:", ret)  # 0 - успех

Проблема: os.system не захватывает вывод команды. Для получения вывода используйте os.popen (устарел) или subprocess.check_output.

Расширенные примеры использования модуля os

Пример 1: Эффективное сканирование каталогов с os.scandir

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

Пример
import os

path = "/tmp"
with os.scandir(path) as entries:
    for entry in entries:
        if entry.is_file() and entry.name.endswith('.txt'):
            stat = entry.stat()
            print(f"{entry.name}: {stat.st_size} байт, изменён {stat.st_mtime}")
файл1.txt: 1024 байт, изменён 1700000000.0
файл2.txt: 2048 байт, изменён 1700000100.0

Пример 2: Передача данных между файловыми дескрипторами через os.sendfile

os.sendfile (доступен в Unix) копирует данные из одного файлового дескриптора в другой на уровне ядра, минуя пользовательское пространство. Используется для высокопроизводительной передачи больших файлов.

Пример
import os

src = open('bigfile.bin', 'rb')
dst = open('copy.bin', 'wb')
try:
    os.sendfile(dst.fileno(), src.fileno(), 0, 10**6)  # копировать 1 МБ
finally:
    src.close()
    dst.close()
print('Файл скопирован через sendfile')
Файл скопирован через sendfile

Пример 3: Получение подробной информации о файле с os.stat

os.stat возвращает объект stat_result с полями st_mode (права и тип), st_uid, st_gid, st_size, st_atime, st_mtime, st_ctime и др. Это полезно для мониторинга и аудита.

Пример
import os
import time

file = 'example.py'
if os.path.isfile(file):
    s = os.stat(file)
    size_kb = s.st_size / 1024
    mod_time = time.ctime(s.st_mtime)
    print(f"Размер: {size_kb:.2f} КБ")
    print(f"Последнее изменение: {mod_time}")
    print(f"Права: {oct(s.st_mode & 0o777)}")  # маска разрешений
Размер: 12.34 КБ
Последнее изменение: Mon Jan 20 10:15:30 2025
Права: 0o644

Пример 4: Безопасное переименование и замена файлов

os.rename(src, dst) заменяет существующий dst только если операция атомарна (на большинстве файловых систем). os.replace(src, dst) делает это атомарно даже если dst существует, что безопаснее.

Пример
import os

old = 'temp.txt'
new = 'final.txt'
# Атомарно заменить final.txt на temp.txt
try:
    os.replace(old, new)
    print(f"{old} заменён на {new}")
except OSError as e:
    print(f"Ошибка: {e}")
temp.txt заменён на final.txt

Пример 5: Создание жёстких и символических ссылок

os.link(src, dst) создаёт жёсткую ссылку (на одной файловой системе), os.symlink(src, dst) - символическую. Используется при организации бэкапов или кэшей.

Пример
import os

original = 'data.txt'
symlink_name = 'link_to_data'
# Создать символическую ссылку
os.symlink(original, symlink_name)
print("Симлинк создан:", symlink_name)
# Проверить, является ли путь ссылкой
print("Является ли симлинком?", os.path.islink(symlink_name))
Симлинк создан: link_to_data
Является ли симлинком? True

Пример 6: Изменение прав доступа и владельца

Функции os.chmod(path, mode) и os.chown(path, uid, gid) меняют разрешения и владельца. Требуются соответствующие привилегии.

Пример
import os

file = 'private.log'
# Установить права только для владельца (чтение+запись)
os.chmod(file, 0o600)
# Изменить владельца на uid=1000, gid=1000 (если есть права root)
# os.chown(file, 1000, 1000)
print(f"Права изменены: {oct(os.stat(file).st_mode & 0o777)}")
Права изменены: 0o600

Библиотека OS для Python - comments

En
библиотека os python (python)