3.5. Потоковый ввод, вывод. Работа с текстовыми файлами. JSON
- Что такое стандартный поток ввода и как с ним работать в Python
- Подключение stdin
- Какие методы позволяют считывать и записывать данные из текстовых файлов
- Почему важно использовать менеджер контекста with при работе с файлами
- Как устроен формат JSON и чем он отличается от обычного текста
- Как использовать модуль json для чтения и записи структурированных данных
- Что дальше
В этой статье вы научитесь считывать данные не только с клавиатуры, но и из файлов, а также записывать результаты работы программ обратно в текстовые и JSON-файлы. Разберётесь, как устроен стандартный поток ввода, научитесь использовать функции open(), read(), write() и менеджер контекста with. Кроме того, освоите работу с форматом JSON — научитесь читать и сохранять структурированные данные с помощью модуля json. Эти знания помогут вам строить программы, которые взаимодействуют с внешними источниками данных и сохраняют результаты в удобном виде.
Ключевые вопросы статьи
- Что такое стандартный поток ввода и как с ним работать в Python?
- Какие методы позволяют считывать и записывать данные из текстовых файлов?
- Почему важно использовать менеджер контекста with при работе с файлами?
- Как устроен формат JSON и чем он отличается от обычного текста?
- Как использовать модуль json для чтения и записи структурированных данных?
Что такое стандартный поток ввода и как с ним работать в Python
Ранее вы уже использовали функцию input() для чтения данных с клавиатуры. Этот способ хорош, если вы точно знаете, сколько строк нужно ввести или как выглядит строка для завершения ввода.
В таких случаях помогает стандартный поток ввода — stdin. Это поток, в который попадают все строки, вводимые пользователем. Программа может забирать их одну за другой, пока не достигнет конца ввода.
Подключение stdin
Чтобы использовать stdin, его нужно импортировать:
from sys import stdin
Поскольку stdin — это итератор, по его строкам можно пройти в цикле:
from sys import stdin
lines = []
for line in stdin:
lines.append(line)
print(lines)
Запустим программу и введём следующие данные:
Первая
Вторая
Третья
Чтобы завершить ввод:
- в Windows — нажмите
Ctrl + Z, затемEnter; - в Linux и macOS — нажмите
Ctrl + D.
Результат работы программы:
['Первая\n', 'Вторая\n', 'Третья\n']
Обратите внимание: каждая строка заканчивается символом перехода на новую строку (\n). Если он мешает, его можно удалить:
from sys import stdin
lines = []
for line in stdin:
lines.append(line.rstrip("\n"))
print(lines)
# Теперь результат:
# ['Первая', 'Вторая', 'Третья']
Чтение всех строк сразу
Если не нужен поэлементный перебор, можно считать все строки сразу с помощью readlines():
from sys import stdin
lines = stdin.readlines()
print(lines)
Чтение всего ввода в одну строку
from sys import stdin
text = stdin.read()
print([text])
# Пример вывода:
# ['Первая\nВторая\nТретья\n']
Здесь результат обёрнут в список, чтобы явно показать символы перехода на новую строку. Переменная text содержит весь ввод целиком — со всеми символами \n.
Какие методы позволяют считывать и записывать данные из текстовых файлов
Работа с файлами позволяет программам получать данные из внешних источников и сохранять результаты. Python предоставляет удобные инструменты для этого.
Что такое файл
Файл — это именованная область данных на диске. Данные в нём хранятся как последовательность байтов. Если файл текстовый, его можно интерпретировать как последовательность символов. Для корректной работы с символами нужно знать кодировку (чаще всего используется UTF-8).
Функция open()
open(file, mode='r', encoding=None)
Аргумент mode определяет режим доступа к файлу:
'r'— чтение (по умолчанию). Файл должен существовать, иначе будет ошибка.'w'— запись с очисткой содержимого. Если файл существует, его содержимое удаляется. Если не существует — создаётся.'a'— добавление в конец файла. Новый текст будет дописан после уже имеющегося. Если файл не существует — создаётся.'r+'— чтение и запись, без удаления содержимого. Файл должен существовать. Запись идёт поверх существующего текста, начиная с начала файла.'w+'— чтение и запись, с удалением содержимого. Файл очищается или создаётся заново. Подходит, если вы хотите сначала записать, а потом прочитать.'a+'— чтение и добавление. Файл открывается в режиме добавления, но можно также его читать. При записи — курсор всегда в конце.
Важно
В Windows по умолчанию используется кодировка cp1251, поэтому нужно всегда явно указывать кодировку UTF-8, если вы хотите, чтобы программа работала кросс-платформенно.
Пример: открытие файла для чтения
Допустим, у нас есть файл input_1.txt, содержащий следующий текст:
Привет!
Это пример текстового файла.
А это - последняя строка, которая заканчивается переходом на новую.
Прочитаем его содержимое:
file_in = open("input_1.txt", encoding="UTF-8")
for line in file_in:
print(line)
file_in.close()
Построчное чтение файла
По открытому файлу можно пройти в цикле:
file_in = open("input_1.txt", encoding="UTF-8")
for line in file_in:
print(line)
file_in.close()
Почему появляются пустые строки
Мы ожидали, что строки выведутся одна под другой. Но фактически на экране будет:
Привет!
Это пример текстового файла.
А это - последняя строка, которая заканчивается переходом на новую.
Причина: каждая строка из файла уже заканчивается символом переноса строки \n, а функция print() по умолчанию тоже добавляет \n. В результате между строками получается двойной отступ.
Как это исправить
Можно удалить символ переноса в конце строки с помощью .rstrip("\n"):
print(line.rstrip("\n"))
Теперь вывод будет выглядеть так:
Привет!
Это пример текстового файла.
А это - последняя строка, которая заканчивается переходом на новую.
Всё ровно — без лишних пустых строк.
Почему важно использовать менеджер контекста with при работе с файлами
Обычно после работы с файлом его нужно закрывать вручную:
file_in = open("input_1.txt", encoding="UTF-8")
# ... работа с файлом ...
file_in.close()
Если этого не сделать, файл может остаться открытым:
- он будет заблокирован для других программ;
- данные могут не сохраниться сразу;
- при ошибке в коде close() может не выполниться вовсе.
Безопасный способ — использовать with
После работы с файлом его необходимо закрыть. Это особенно важно, потому что:
- незакрытый файл может остаться заблокированным для других программ;
- данные из буфера могут не записаться полностью.
Однако, использование метода close() не всегда решает данные проблемы, ведь при возникновении ошибки до завершения работы с файлом, он останется открытым.
Чтобы избежать таких проблем, всегда используйте менеджер контекста – конструкцию with. Она гарантирует, что файл будет закрыт автоматически.
with open("input_1.txt", encoding="UTF-8") as file_in:
for line in file_in:
print(line.rstrip("\n"))
Почему это ещё и быстрее
Следует помнить о том, что устройство хранения данных является самым медленным в компьютере, так что частые операции с файлами будут снижать скорость работы вашей программы.
Поэтому, если позволяют ресурсы компьютера (объём оперативной памяти), файл лучше прочитать сразу целиком, работать с ним в оперативной памяти и записывать в файл полностью полученный результат.
Чтение файла целиком — списком строк
Для получения полного списка строк текстового файла используется метод readlines():
with open("input_1.txt", encoding="UTF-8") as file_in:
lines = file_in.readlines()
print(lines)
# Вывод программы:
# ['Привет!\n', 'Это пример текстового файла.\n', 'А это -- последняя строка, которая должна закончиться переходом на новую.\n']
Чтение первых символов файла
Для чтения символов файла в строковую переменную используется метод read().
Прочитаем 10 символов файла:
with open("input_1.txt", encoding="UTF-8") as file_in:
symbols = file_in.read(10)
print([symbols])
# Вывод программы:
# ['Привет!\nЭт']
Если в методе read() не указать количество считываемых символов, то прочитается весь файл.
Запись в файл
Для записи в файл его необходимо сначала открыть в режиме записи (выше мы говорили о режимах доступа).
Для записи данных из строковой переменной используется метод write():
with open("output_1.txt", "w", encoding="UTF-8") as file_out:
n = file_out.write("Это первая строка\nА вот и вторая\nИ третья -- последняя\n")
print(n)
Что делает программа:
- Открывает (или создаёт) файл
output_1.txtв режиме записи. Если файл уже существует, его содержимое будет удалено. - Записывает в него одну строку с символами перевода строки
\nвнутри — это создаст три строки в файле. - Метод
write()возвращает количество записанных символов, включая все пробелы и\n. - Эта длина (в нашем случае —
55) выводится в консоль.
Запись списка строк
Для записи строк из списка в файл используется метод writelines(). Этот метод записывает строки в файл по очереди, без разделителя. Пример его использования:
lines = ["Это первая строка\n", "А вот и вторая\n", "И третья - последняя\n"]
with open("output_2.txt", "w", encoding="UTF-8") as file_out:
file_out.writelines(lines)
# Содержимое выходного файла:
# Это первая строка
# А вот и вторая
# И третья - последняя
Использование print() для записи в файл
Функция print() может быть использована для вывода данных в файл.
Для этого нужно передать ей в аргумент file файловый объект:
with open("output_3.txt", "w", encoding="UTF-8") as file_out:
print("Вывод в файл с помощью функции print()", file=file_out)
# Содержимое выходного файла:
# Вывод в файл с помощью функции print()
Как устроен формат JSON и чем он отличается от обычного текста
Существуют такие форматы текстовых файлов, которые могут хранить в себе информацию, структурированную по некоторым правилам.
Один из таких форматов — JSON (англ. JavaScript Object Notation). Как видно из названия, он был создан для языка JavaScript, но в настоящее время независим от него и может использоваться практически с любым языком программирования.
Для значений в JSON можно использовать:
- строки — для обозначения строки используются строго двойные кавычки;
- числа — целые и вещественные;
- логические значения
trueиfalse— записываются, в отличие от Python, со строчной буквы.
Для хранения неупорядоченных наборов данных в JSON можно использовать записи — пары «ключ: значение» (аналог словаря в Python). Также можно хранить упорядоченные последовательности значений (аналог списка в Python).
Посмотрим, что представляет собой JSON-файл, на примере. Предположим, что нужно хранить структурированную информацию о студентах следующего вида:
- фамилия (last_name),
- имя (first_name),
- отчество (patronymic),
- дата рождения (date_of_birth),
- номер группы (group_number),
- список номеров телефонов (phones_numbers).
Тогда список с информацией о студентах можно представить в следующем виде:
[
{
"last_name": "Иванов",
"first_name": "Иван",
"patronymic": "Иванович",
"date_of_birth": "01.01.2001",
"group_number": 1,
"phone_numbers": [
"+7 111 111 1111",
"+7 111 111 1112"
]
},
{
"last_name": "Петров",
"first_name": "Пётр",
"patronymic": "Петрович",
"date_of_birth": "10.10.2001",
"group_number": 1,
"phone_numbers": [
"+7 111 111 1113",
"+7 111 111 1114"
]
}
]
Мы видим, что в JSON-файле находится список из двух записей, очень похожих на словарь Python.
Как использовать модуль json для чтения и записи структурированных данных
Для более удобной работы с JSON-файлами существует стандартный модуль json.
Он позволяет преобразовать данные из JSON-файла в вашей программе в стандартные типы данных Python, а также способен выполнить обратную операцию — для записи данных обратно в файл.
Чтение JSON-файла
Для чтения JSON-файлов используется метод load(), считывающий весь файл целиком и возвращающий объект стандартного типа данных Python:
import json
from pprint import pprint
with open("data.json", encoding="UTF-8") as file_in:
records = json.load(file_in)
pprint(records)
#Вывод программы:
# [{'date_of_birth': '01.01.2001',
# 'first_name': 'Иван',
# 'group_number': 1,
# 'last_name': 'Иванов',
# 'patronymic': 'Иванович',
# 'phone_numbers': ['+7 111 111 1111', '+7 111 111 1112']},
# {'date_of_birth': '10.10.2001',
# 'first_name': 'Пётр',
# 'group_number': 1,
# 'last_name': 'Петров',
# 'patronymic': 'Петрович',
# 'phone_numbers': ['+7 111 111 1113', '+7 111 111 1114']}]
Из примера видно, что JSON-файл был преобразован в список словарей, а каждый словарь — это запись с информацией о студенте. Для обработки таких объектов можно применять стандартные методы и операции Python.
Запись JSON-файла
После того как вы изменили структуру данных в программе (например, обновили одно из полей словаря), результат можно сохранить обратно в JSON-файл.
Для этого используется метод dump() из модуля json. Он преобразует объект Python в строку в формате JSON и записывает её в файл.
Рассмотрим важные аргументы функции json.dump():
ensure_ascii— еслиTrue(по умолчанию), все не-ASCII-символы сохраняются как\uXXXX. ПриFalseсохраняются как есть (нужно для букв на кириллице).indent— задаёт отступы для форматирования:
—None(по умолчанию) — весь JSON в одну строку;
— число — количество пробелов на уровень вложенности.sort_keys— если True, ключи в словаре будут отсортированы.
Пример
Изменим поле group_number у второго студента и запишем обновлённые данные обратно в файл:
import json
with open("data.json", encoding="UTF-8") as file_in:
records = json.load(file_in)
records[1]["group_number"] = 2
with open("data.json", "w", encoding="UTF-8") as file_out:
json.dump(records, file_out, ensure_ascii=False, indent=2)
Содержимое файла data.json после работы программы:
[
{
"last_name": "Иванов",
"first_name": "Иван",
"patronymic": "Иванович",
"date_of_birth": "01.01.2001",
"group_number": 1,
"phone_numbers": [
"+7 111 111 1111",
"+7 111 111 1112"
]
},
{
"last_name": "Петров",
"first_name": "Пётр",
"patronymic": "Петрович",
"date_of_birth": "10.10.2001",
"group_number": 2,
"phone_numbers": [
"+7 111 111 1113",
"+7 111 111 1114"
]
}
]
Преобразование ключей словаря
Модуль json автоматически преобразует ключи словаря в строки, если они были, например, целыми числами.
Рассмотрим пример:
import json
records = {
1: "First",
2: "Second",
3: "Third"
}
with open("output.json", "w", encoding="UTF-8") as file_out:
json.dump(records, file_out, ensure_ascii=False, indent=2)
Содержимое файла output.json после работы программы:
{
"1": "First",
"2": "Second",
"3": "Third"
}
Обратите внимание: ключи 1, 2, 3 были целыми числами в Python, но в JSON все ключи обязательно должны быть строками — они были автоматически преобразованы при записи.
Что дальше
Теперь вы умеете считывать данные из стандартного потока ввода, читать и записывать текстовые файлы, работать с кодировкой, а также обрабатывать структурированные данные в формате JSON. Вы познакомились с менеджером контекста with, поняли, как важно закрывать файл, и научились использовать модуль json для преобразования данных.
Далее — финальная статья третьей главы, в котором мы кратко подведём итоги.
Ключевые выводы статьи
- Стандартный поток ввода
stdinпозволяет считывать произвольное количество строк из консоли, что удобно при обработке входных данных без заранее известного объёма.- С помощью методов
read(),readlines()иwrite()можно считывать и записывать данные из текстовых файлов, построчно или целиком.- Менеджер контекста
withгарантирует, что файл будет закрыт автоматически, даже если в программе произойдёт ошибка.- Формат JSON используется для хранения структурированных данных и поддерживается большинством языков программирования, включая Python.
- Модуль
jsonпозволяет легко преобразовывать JSON-файлы в объекты Python (load) и обратно (dump), а также управлять форматированием и кодировкой при записи.