Работа с файлами

Пока программа работает только с переменными, её данные живут в оперативной памяти и исчезают после завершения процесса. Для робототехнического эксперимента этого часто недостаточно: нужно сохранить расстояния с датчика, вспомнить коэффициенты калибровки при следующем запуске или передать журнал измерений в программу построения графиков. Файл позволяет оставить такие данные на накопителе и снова открыть их позже.
Python открывает файл функцией open() или методом Path.open(). Режим определяет, будет программа читать, перезаписывать или дополнять данные. Конструкция with закрывает файл после выхода из блока даже при ошибке, а encoding="utf-8" делает работу с русским текстом предсказуемой.
Зачем это нужно
Представим мобильного робота, который раз в десятую долю секунды измеряет расстояние до препятствия. Одного текущего числа хватает для экстренной остановки, но не для разбора эксперимента. После заезда инженеру полезно узнать:
- когда робот приблизился к стене;
- как менялись показания датчика;
- сработал ли порог остановки вовремя;
- какие настройки использовались во время испытания.
Программа может записывать поток измерений в CSV-файл, а настройки — в JSON. После перезапуска она загрузит параметры снова, а таблицу измерений можно будет открыть отдельным скриптом и проанализировать.
Главная идея
Файл похож на подписанный контейнер, который остаётся после завершения программы. Работа с ним состоит из четырёх действий:
путь -> открыть в нужном режиме -> прочитать или записать -> закрыть
В Python эти действия обычно объединяет блок with:
from pathlib import Path
message_path = Path("status.txt")
with message_path.open("w", encoding="utf-8") as status_file:
status_file.write("Стенд готов к запуску\n")
После окончания блока объект status_file закрыт. Это освобождает связанный с ним системный ресурс и завершает обычную запись буферизованных данных.
Путь указывает, где находится файл. Относительный путь вроде data/run.csv отсчитывается от текущей рабочей папки процесса. Абсолютный путь начинается от корня файловой системы. Для учебных проектов удобнее собирать пути через pathlib.Path, не склеивая разделители вручную.
Выбираем режим открытия
Второй аргумент open() задаёт режим. Ошибка в одной букве может стереть старый журнал, поэтому режим выбирают до записи.
| Режим | Действие | Если файла нет | Что будет со старым содержимым |
|---|---|---|---|
r | чтение | FileNotFoundError | останется без изменений |
w | запись | файл будет создан | содержимое будет очищено |
a | добавление в конец | файл будет создан | старые данные сохранятся |
x | создание нового файла | файл будет создан | существующий файл вызовет FileExistsError |
b в составе режима | двоичные данные, например rb | зависит от основного режима | программа работает с bytes, а не со строками |
Если режим не указан, используется r. В текстовом режиме стоит явно задавать кодировку:
from pathlib import Path
notes_path = Path("experiment.txt")
with notes_path.open("a", encoding="utf-8") as notes_file:
notes_file.write("Порог остановки: 18 см\n")
Режим a подходит для последовательного журнала: новый запуск добавит строку, а не удалит прошлые записи. Для изображения, прошивки или другого двоичного формата используют режим с b; параметр encoding тогда не задают.
Path помогает не путать папки и файлы
Модуль pathlib представляет путь объектом. Такой объект умеет присоединять части пути, создавать папки и открывать файл:
from pathlib import Path
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
report_path = data_dir / "report.txt"
report_path.write_text("Испытание завершено\n", encoding="utf-8")
report = report_path.read_text(encoding="utf-8")
print(report.strip())
Методы write_text() и read_text() удобны для небольших файлов. Когда журнал может стать большим, лучше читать его построчно: тогда программа не загружает всё содержимое в память одновременно.
from pathlib import Path
log_path = Path("data") / "distance.log"
if log_path.exists():
with log_path.open("r", encoding="utf-8") as log_file:
for line_number, line in enumerate(log_file, start=1):
clean_line = line.strip()
if clean_line:
print(line_number, clean_line)
Проверка exists() полезна для ожидаемо необязательного файла. Если отсутствие файла означает неисправность проекта, ошибку лучше не скрывать, а обработать и сообщить пользователю, какой путь не найден.
Текст, CSV и JSON решают разные задачи
Формат выбирают по структуре данных, а не по расширению, которое выглядит привычнее.
| Формат | Что удобно хранить | Пример в робототехнике | Особенность |
|---|---|---|---|
| обычный текст | сообщения и простой журнал | события запуска и остановки | легко читать человеку, структуру задаёт программа |
| CSV | строки с одинаковыми столбцами | время, расстояние, скорость | удобно открывать как таблицу |
| JSON | именованные настройки и простые наборы значений | настройки датчиков и режимов | сохраняет структуру базовых данных Python |
Записываем измерения в CSV
Стандартный модуль csv учитывает правила табличного формата. При открытии файла документация рекомендует передавать newline="":
import csv
from pathlib import Path
samples = [
(0.0, 42.5),
(0.1, 37.8),
(0.2, 29.4),
(0.3, 17.9),
]
log_path = Path("data") / "distance.csv"
log_path.parent.mkdir(exist_ok=True)
with log_path.open("w", encoding="utf-8", newline="") as log_file:
writer = csv.writer(log_file)
writer.writerow(["time_s", "distance_cm"])
writer.writerows(samples)
Первая строка содержит названия столбцов. Остальные строки имеют одинаковый порядок значений, поэтому следующий скрипт сможет восстановить смысл каждого числа.
Сохраняем настройки в JSON
JSON подходит для набора именованных параметров. В Python такой набор удобно записать в фигурных скобках: слева имя параметра, справа его значение. Подробные коллекции не выделяются в отдельный урок, поэтому здесь достаточно читать запись буквально как «ключ -> значение». Стандартный модуль json выполняет сериализацию — превращает структуру Python в текстовое представление — и обратную десериализацию.
import json
from pathlib import Path
settings = {
"stop_distance_cm": 18,
"max_speed": 0.45,
"sound_enabled": True,
}
settings_path = Path("data") / "robot-settings.json"
settings_path.parent.mkdir(exist_ok=True)
with settings_path.open("w", encoding="utf-8") as settings_file:
json.dump(settings, settings_file, ensure_ascii=False, indent=2)
with settings_path.open("r", encoding="utf-8") as settings_file:
loaded_settings = json.load(settings_file)
print(loaded_settings["stop_distance_cm"])
Параметр indent=2 делает файл удобнее для проверки человеком. ensure_ascii=False оставляет русские символы читаемыми; сам JSON-файл при этом открывается в UTF-8.

Пример: журнал безопасной остановки
Соединим показания датчика и файл. Здесь список имитирует уже полученные измерения; в настоящем роботе числа приходят из драйвера датчика.
import csv
from pathlib import Path
STOP_DISTANCE_CM = 18.0
measurements = [31.2, 24.7, 17.6, 16.9]
log_path = Path("data") / "safety-run.csv"
log_path.parent.mkdir(exist_ok=True)
with log_path.open("w", encoding="utf-8", newline="") as log_file:
writer = csv.DictWriter(
log_file,
fieldnames=["step", "distance_cm", "motor_command"],
)
writer.writeheader()
for step, distance_cm in enumerate(measurements):
command = "stop" if distance_cm < STOP_DISTANCE_CM else "forward"
writer.writerow(
{
"step": step,
"distance_cm": distance_cm,
"motor_command": command,
}
)
Теперь решение программы связано с исходным измерением. Инженер может проверить строку, на которой команда сменилась с forward на stop, и сравнить её с выбранным порогом.
Что делать с ошибками чтения
Файл может отсутствовать, быть повреждённым или находиться в недоступной папке. Обрабатывайте только те ошибки, для которых программа знает понятное действие:
import json
from pathlib import Path
settings_path = Path("data") / "robot-settings.json"
try:
with settings_path.open("r", encoding="utf-8") as settings_file:
settings = json.load(settings_file)
except FileNotFoundError:
print("Файл настроек не найден. Используются безопасные значения.")
settings = {"stop_distance_cm": 15}
except json.JSONDecodeError as error:
print(f"JSON повреждён: строка {error.lineno}, столбец {error.colno}")
settings = {"stop_distance_cm": 15}
print(settings["stop_distance_cm"])
Значение по умолчанию должно быть действительно безопасным для конкретного робота. Универсального расстояния остановки нет: оно зависит от скорости, торможения, датчика и условий стенда.
Что запомнить о файлах
- Сначала определите путь, формат и режим открытия.
- Для текста явно задавайте
encoding="utf-8". - Используйте
with, чтобы файл корректно закрывался. - Помните, что
wочищает существующее содержимое, аaдописывает в конец. - Читайте большой журнал построчно.
- Храните табличные измерения в CSV, а структурированные настройки — в JSON.
- Не скрывайте ошибку, если программа не знает, как безопасно продолжить работу.
Практика
Задание 1. Журнал освещённости
Создайте список из десяти пар «время — освещённость». Запишите его в CSV с заголовками столбцов. Затем прочитайте файл и выведите только строки, где освещённость ниже выбранного порога.
Задание 2. Настройки движения
Сохраните в JSON максимальную скорость, дистанцию остановки и логическое значение звукового сигнала. Напишите отдельный фрагмент, который загружает файл и проверяет наличие каждого обязательного ключа.
Задание 3. Защита старого эксперимента
Измените программу журнала так, чтобы она не могла случайно перезаписать уже существующий файл. Продумайте сообщение, которое увидит оператор при конфликте имён.
Задание 4. Анализ маршрута
В текстовом файле каждая строка содержит одну команду: forward, left, right или stop. Подсчитайте количество команд каждого вида, не загружая файл целиком в список.
Проверьте себя
- Чем режим
wотличается отaиx? - Зачем указывать
encoding="utf-8"? - Почему файл удобно открывать внутри
with? - Когда CSV подходит лучше JSON?
- Чем чтение
read_text()отличается от перебора файла в цикле? - Какая ошибка возникает при чтении отсутствующего файла?
- Почему значение по умолчанию для робота должно быть безопасным?
Сначала ответьте без подсказки. Ответ можно считать полным, если вы:
- формулируете основную мысль своими словами;
- называете важные условия, ограничения или меры безопасности;
- для схемы, кода или расчёта показываете ход решения и ожидаемый результат.
Если один из пунктов объяснить не получается, найдите соответствующую главу статьи, перечитайте её и повторите ответ.
Словарь статьи
- Файл — именованная последовательность данных на накопителе.
- Путь — указание расположения файла или папки.
- Относительный путь — путь, который отсчитывается от текущей рабочей папки процесса.
- Режим открытия — правило чтения, записи, добавления или создания файла.
- Кодировка — способ сопоставить символы и байты; для учебных текстовых файлов используем UTF-8.
- Контекстный менеджер — объект, который управляет входом в блок
withи выходом из него. - Сериализация — преобразование структуры данных в форму для хранения или передачи.
- CSV — текстовый формат строк с одинаковым набором столбцов.
- JSON — текстовый формат для структурированных данных: объектов, массивов, строк, чисел и логических значений.
Связанные темы
- Функции — как вынести чтение и запись в отдельные операции.
- Классы — как хранить состояние объекта и методы работы с ним.
- Библиотеки и виртуальные окружения — стандартные модули, сторонние пакеты и изоляция проекта.
- Циклы — как обрабатывать журнал построчно.
Источники
- Python 3.14. Чтение и запись файлов: https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files
- Python 3.14. Встроенная функция
open(): https://docs.python.org/3/library/functions.html#open - Python 3.14.
pathlib— объектные пути файловой системы: https://docs.python.org/3/library/pathlib.html - Python 3.14. Модуль
csv: https://docs.python.org/3/library/csv.html - Python 3.14. Модуль
json: https://docs.python.org/3/library/json.html - Python 3.14. Конструкция
with: https://docs.python.org/3/reference/compound_stmts.html#the-with-statement