Работа с файлами. Сериализация: json и pickle
Contents
Работа с файлами. Сериализация: json
и pickle
#
Файловый объект. Функция open
#
Для работы с файлами существует функция open, которая создаёт файловый объект. Единственный обязательный параметр этой функции path
— путь к файлу. Очень важный опциональный параметр mode
отвечает за режим открытия файла.
Символ |
Значение |
---|---|
|
Открыть на чтение (по умолчанию) |
|
Открыть на запись (содержимое существующего файла уничтожается) |
|
Создать файл и открыть на запись (ошибка, если файл существует) |
|
Открыть файл на дозапись (если файл существует, то дозаписывать в конец файла) |
|
Открыть как бинарный файл |
|
Открыть как текстовый файл (по умолчанию) |
|
Открыть на запись и чтение |
По умолчанию функцию open
открывает файл как текстовый для чтения. В качестве примера создадим файл "first_file.txt"
в папке "tmp"
. Для этого сначала убедимся в том, что папка существует и создадим строку path
, представляющую путь до будущего файла.
import os
folder = "tmp"
filename = "first_file.txt"
path = os.path.join(folder, filename)
os.makedirs(folder, exist_ok=True)
Теперь создадим файловый объект, запишем в него текст. Для этого необходимо открыть файл в режиме на запись в текстовом режиме (флаг "wt"
или "w"
, т.к. текстовый режим подразумевается по умолчанию), записать строки текста в него методом write, а в конце обязательно закрыть файл методом close.
f = open(path, "w")
f.write(
"""Первая строка.
Вторая строка.
Последняя строка."""
)
f.close()
Теперь, чтобы убедиться в успешном создании файла, можно повторить эти операции, но на чтение. Как и прежде, в начале создаётся файловый объект встроенной функцией open и в конце закрыть его методом close, но в этот раз режим открытия на чтение, а значит в качестве параметра можно передать "rt"
, "r"
или не передать ничего, так как по умолчанию подразумевается открытие на чтение в текстовом режиме. Считывать содержимое из файла можно несколькими методами, но для начала рассмотрим самый простой — чтение сразу всего содержимого методом read.
f = open(path)
content = f.read()
print(content)
f.close()
Первая строка.
Вторая строка.
Последняя строка.
Видим, что все операции завершились успешно.
Контекстный менеджер with
#
При создании файлового объекта в явном виде необходимо следить за тем, чтобы в самом конце вызвать метод close. Это принципиально по нескольким причинам. Во-первых, считается хорошей практикой освобождать ресурсы (возвращать их под управление операционной системы), как только в них пропала нужда. Во-вторых, если исполнение программы прекратится в экстренном режиме (например, из-за логической ошибки в программе или в результате технического сбоя в аппаратном обеспечении), то риски повреждения незакрытого файла многократно растут.
Тем не менее в хорошем коде python
вы встретите вызов метода close в явном виде очень редко. Все это из-за того, что хорошей практикой является использование контекстного менеджера with, который не только автоматически освобождает файловый ресурс по выходу из соответствующего блока, но и проследит за освобождением ресурсов даже в том случае, если при работе программы возникла логическая ошибка и программа упала. Для работы с файлами обычно используется приблизительно следующая конструкция.
with open(path) as name:
первая строка блока with
...
последняя строка блока with
первая инструкция после блока with # здесь файл гарантировано закрыт
В заголовке блока with
открывается файл, и результирующий файловый объект связывается с именем name
. Этот файл будет открыт до тех пор, пока программа не покинет следующий за заголовком блок кода. Как только программы этот блок покидает (естественным образом или в результате распространения исключения), файл автоматически закрывается и имя name
освобождается.
Считаем содержимое созданного в предыдущем разделе файла с блоком with
.
with open(filename) as f:
print(f.read())
Первая строка.
Вторая строка.
Последняя строка.
Если возможно, то всегда рекомендуется открывать файлы именно с помощью блока with
.
Итерация по текстовому файлу#
Читать содержимое текстового файла можно несколько способами, кроме уже упомянутого метода read, есть также методы readline (чтение одной строки) и readlines (возвращает список всех строк файла). Но в подавляющем большинстве случаев содержимое файла считывают построчно, просто итерируясь по файловому объекту.
with open(filename) as f:
for line in f:
print(line)
Первая строка.
Вторая строка.
Последняя строка.
Видим, что при печати строки оказались разреженными. Дело в том, что при итерации в переменную line
попадает вся считанная строка целиком, включая управляющий символ "\n"
, если он есть в конце. От этого можно избавиться методом rstrip.
Формат JSON
#
Нередко возникает необходимость сохранять и передавать структурированные данные в текстовом виде. Хотя можно разработать и свою схему сохранения данных, но гораздо удобнее использовать для таких целей форматом JSON.
JSON (англ. JavaScript Object Notation, обычно произносится как /ˈdʒeɪsən/ JAY-sən) — текстовый формат обмена данными, основанный на JavaScript. Как и многие другие текстовые форматы, JSON легко читается людьми. Источник: Wikipedia.
JSON изначально был придуман для сериализации объектов языка javascript
, но со временем стал применяться и в других языках программирования. Его применение распространено и в python
, т.к. две основные структуры данных в python
— списки и словари — являются и основными блоками синтаксиса JSON
.
За работу с JSON
в python
отвечает модуль стандартной библиотеки json. Основные методы этого модуля:
json.dumps сериализует объект в строку;
json.dump — то же самое, но сразу записывает в файл;
json.loads десериализует строку
json
и создаёт объект;json.load десериализует содержимое файла
json
.
Рассмотрим самый простой пример с ними: создадим список и словарь и сериализуем их в строки.
import json
a_list = [1, 1., "a"]
json_list = json.dumps(a_list)
a_dict = {
"key1": "value1",
"key2": "value2"
}
json_dict = json.dumps(a_dict)
print(f"json представление для списка: {json_list}")
print(f"json представление для словаря: {json_dict}")
Теперь исходные объекты можно восстановить обратным методом json.loads.
a_list_recovery = json.loads(json_list)
print(a_list_recovery, type(a_list_recovery))
a_dict_recovery = json.loads(json_dict)
print(a_dict_recovery, type(a_dict_recovery))
Из примера видно, что удалось десериализовать объекты из строки json
в исходном виде. Заметим, что между сериализацией и десериализацией строковое представление объекта могло быть сохранено в файл и прочитано обратно, передано по сети интернет и прочитано другим компьютером и т.д.
Коллекции в python
могут быть вложенными друг в друга и json
без проблем справляется с представлением таких вложенных структур.
import json
import os
course_description = {
"lecturer": "Fadeev Egor",
"course": "Computer technologies workshop",
"topics": ["python3", "scientific libraries", "mathematical modeling"],
"where": {
"Faculty": "Faculty of physics",
"room": "5-42"
},
"when": {
"day of week": "Thursday",
"time": "5:05 pm"
},
"number of students": 25
}
os.makedirs("tmp", exist_ok=True)
with open(os.path.join("tmp", "course_description.json"), "w") as f:
json.dump(course_description, f, indent=4)
Если выполнить предыдущую ячейку, то в папке tmp
должен создаться файл course_description.json
со следующим содержимым (с точностью до порядка ключей).
{
"lecturer": "Fadeev Egor",
"course": "Computer technologies workshop",
"topics": [
"python3",
"scientific libraries",
"mathematical modeling"
],
"where": {
"Faculty": "Faculty of physics",
"room": "5-42"
},
"when": {
"day of week": "Thursday",
"time": "5:05 pm"
},
"number of students": 25
}