Чтение и запись в файл JSON-объекта
Эта статья научит вас парсить данные из JSON. Также вы узнаете, как читать и записывать в файл данные JSON.
За последние 5-10 лет формат JSON был одним из самых популярных способов сериализации данных (если не самым популярным). Особенно в веб-разработке. С этим форматом вы столкнетесь при работе с REST API, конфигурациями приложений или базами данных.
Несомненно, знать принципы работы JSON — очень важно. В какой-то момент вы обязательно с ним встретитесь. Возможно, вы захотите узнать, как читать и записывать JSON в файл. Все эти действия — очень простые. В этом вы убедитесь, разобрав следующие примеры.
Запись JSON в файл
Самый простой способ записать JSON в файл — использовать словарь. Они могут хранить вложенные словари, массивы, булевы значения и другие типы данных вроде целых чисел и строк. Более детальный список поддерживаемых типов данных можно найти здесь.
Во встроенной библиотеке json есть «волшебный» метод, который позволяет конвертировать словари в сериализованную JSON-строку.
import json data = <> data['people'] = [] data['people'].append(< 'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska' >) data['people'].append(< 'name': 'Larry', 'website': 'pythonist.ru', 'from': 'Michigan' >) data['people'].append(< 'name': 'Tim', 'website': 'pythonist.ru', 'from': 'Alabama' >) with open('data.txt', 'w') as outfile: json.dump(data, outfile)
После импорта библиотеки json мы объявляем несколько словарей и наполняем их данными. Самая важная часть — в конце программы. Здесь мы используем оператор with , чтобы открыть файл. После этого мы используем метод json.dump , чтобы записать наши словари в файл.
Вторым аргументом может быть любой файлоподобный объект — даже если это не совсем файл. Например, сокет. Его можно открыть, закрыть и записать так же, как и файл. С подобным вариантом использования JSON вы точно столкнетесь — это важно запомнить.
Стоит упомянуть и о вариации метода json.dump — json.dumps . Этот метод позволяет вернуть JSON-строку, а не записывать ее в файл. Это может быть полезно, если вы хотите изменить JSON-строку. (например, зашифровать)
Чтение JSON из файла
Чтение JSON из файла такое же простое, как и запись. С помощью библиотеки json мы можем спарсить JSON-строку прямо из файла. В этом примере мы парсим данные и выводим их в консоль:
import json with open('data.txt') as json_file: data = json.load(json_file) for p in data['people']: print('Name: ' + p['name']) print('Website: ' + p['website']) print('From: ' + p['from']) print('')
json.load — очень важный метод, запомните его. С его помощью происходит чтение файла, парс JSON-данных. После этого все данные записываются в словарь и возвращаются вам.
Как и у json.dump , у json.load есть дополнительный метод. Он позволяет работать со строками напрямую, ведь чаще всего у вас не будет файлоподобного объекта, содержащего JSON. Как вы уже догадались, называется он json.loads . Допустим, вы вызываете конечную точку REST с помощью GET, который возвращает строку. Ее мы и можем напрямую передать в json.loads .
Параметры
При сериализации данных в JSON могут возникнуть проблемы. Например, его будет не очень удобно читать, ведь удаляются все пробелы. В большинстве случаев этот вариант вполне хорош, но порой нужно внести небольшие изменения. К примеру, добавить пробелы, чтобы JSON было удобнее читать. У json.load и json.dump есть несколько параметров, которые дают необходимую гибкость. О некоторых из них мы и поговорим.
Pretty-Printing
Сделать JSON более удобочитаемым (pretty-printing) — очень просто. Нужно лишь передать целое число в параметр indent :
import json data = <'people':[<'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska'>]> json.dumps(data, indent=4) < "people": [ < "website": "pythonist.ru", "from": "Nebraska", "name": "Scott" >] >
Это довольно полезно. Особенно если вам часто приходится читать JSON во время работы. Также вы можете использовать использовать команду json.tool прямо в командной строке. Если вы хотите удобочитаемый JSON, наберите в командной строке следующий код:
Сортировка
В JSON объект определяется следующим образом:
Объект — это неупорядоченный набор пар ключ/значение.
То есть, порядок не гарантируется. Но навести его реально. Сделать это можно с помощью передачи True в параметр sort_keys в методах json.dump или json.dumps .
import json data = <'people':[<'name': 'Scott', 'website': 'pythonist.ru', 'from': 'Nebraska'>]> json.dumps(data, sort_keys=True, indent=4) < "people": [ < "from": "Nebraska", "name": "Scott", "website": "pythonist.ru" >] >
ASCII-текст
По умолчанию json.dump проверяет, имеет ли ваш текст в словаре кодировку ASCII. Если присутствуют символы, отличные от ASCII, они автоматически экранируются. Это показано в следующем примере:
import json data = jstr = json.dumps(data, indent=4) print(jstr)
Но это не всегда приемлемо. Во многих случаях вы бы хотели сохранить символы Unicode нетронутыми. Для этого нужно передать в параметр ensure_ascii значение False .
jstr = json.dumps(data, ensure_ascii=False, indent=4) print(jstr)
Работа с файлами в формате JSON#
JSON (JavaScript Object Notation) — это текстовый формат для хранения и обмена данными.
JSON по синтаксису очень похож на Python и достаточно удобен для восприятия.
Как и в случае с CSV, в Python есть модуль, который позволяет легко записывать и читать данные в формате JSON.
Чтение#
"access": [ "switchport mode access", "switchport access vlan", "switchport nonegotiate", "spanning-tree portfast", "spanning-tree bpduguard enable" ], "trunk": [ "switchport trunk encapsulation dot1q", "switchport mode trunk", "switchport trunk native vlan 999", "switchport trunk allowed vlan" ] >
Для чтения в модуле json есть два метода:
- json.load — метод считывает файл в формате JSON и возвращает объекты Python
- json.loads — метод считывает строку в формате JSON и возвращает объекты Python
json.load #
Чтение файла в формате JSON в объект Python (файл json_read_load.py):
import json with open('sw_templates.json') as f: templates = json.load(f) print(templates) for section, commands in templates.items(): print(section) print('\n'.join(commands))
$ python json_read_load.py access switchport mode access switchport access vlan switchport nonegotiate spanning-tree portfast spanning-tree bpduguard enable trunk switchport trunk encapsulation dot1q switchport mode trunk switchport trunk native vlan 999 switchport trunk allowed vlan
json.loads #
Считывание строки в формате JSON в объект Python (файл json_read_loads.py):
import json with open('sw_templates.json') as f: file_content = f.read() templates = json.loads(file_content) print(templates) for section, commands in templates.items(): print(section) print('\n'.join(commands))
Результат будет аналогичен предыдущему выводу.
Запись#
Запись файла в формате JSON также осуществляется достаточно легко.
Для записи информации в формате JSON в модуле json также два метода:
- json.dump — метод записывает объект Python в файл в формате JSON
- json.dumps — метод возвращает строку в формате JSON
json.dumps #
Преобразование объекта в строку в формате JSON (json_write_dumps.py):
import json trunk_template = [ 'switchport trunk encapsulation dot1q', 'switchport mode trunk', 'switchport trunk native vlan 999', 'switchport trunk allowed vlan' ] access_template = [ 'switchport mode access', 'switchport access vlan', 'switchport nonegotiate', 'spanning-tree portfast', 'spanning-tree bpduguard enable' ] to_json = 'trunk': trunk_template, 'access': access_template> with open('sw_templates.json', 'w') as f: f.write(json.dumps(to_json)) with open('sw_templates.json') as f: print(f.read())
Метод json.dumps подходит для ситуаций, когда надо вернуть строку в формате JSON. Например, чтобы передать ее API.
json.dump #
Запись объекта Python в файл в формате JSON (файл json_write_dump.py):
import json trunk_template = [ 'switchport trunk encapsulation dot1q', 'switchport mode trunk', 'switchport trunk native vlan 999', 'switchport trunk allowed vlan' ] access_template = [ 'switchport mode access', 'switchport access vlan', 'switchport nonegotiate', 'spanning-tree portfast', 'spanning-tree bpduguard enable' ] to_json = 'trunk': trunk_template, 'access': access_template> with open('sw_templates.json', 'w') as f: json.dump(to_json, f) with open('sw_templates.json') as f: print(f.read())
Когда нужно записать информацию в формате JSON в файл, лучше использовать метод dump.
Дополнительные параметры методов записи#
Методам dump и dumps можно передавать дополнительные параметры для управления форматом вывода.
По умолчанию эти методы записывают информацию в компактном представлении. Как правило, когда данные используются другими программами, визуальное представление данных не важно. Если же данные в файле нужно будет считать человеку, такой формат не очень удобно воспринимать.
К счастью, модуль json позволяет управлять подобными вещами.
Передав дополнительные параметры методу dump (или методу dumps), можно получить более удобный для чтения вывод (файл json_write_indent.py):
import json trunk_template = [ 'switchport trunk encapsulation dot1q', 'switchport mode trunk', 'switchport trunk native vlan 999', 'switchport trunk allowed vlan' ] access_template = [ 'switchport mode access', 'switchport access vlan', 'switchport nonegotiate', 'spanning-tree portfast', 'spanning-tree bpduguard enable' ] to_json = 'trunk': trunk_template, 'access': access_template> with open('sw_templates.json', 'w') as f: json.dump(to_json, f, sort_keys=True, indent=2) with open('sw_templates.json') as f: print(f.read())
Теперь содержимое файла sw_templates.json выглядит так:
"access": [ "switchport mode access", "switchport access vlan", "switchport nonegotiate", "spanning-tree portfast", "spanning-tree bpduguard enable" ], "trunk": [ "switchport trunk encapsulation dot1q", "switchport mode trunk", "switchport trunk native vlan 999", "switchport trunk allowed vlan" ] >
Изменение типа данных#
Еще один важный аспект преобразования данных в формат JSON: данные не всегда будут того же типа, что исходные данные в Python.
Например, кортежи при записи в JSON превращаются в списки:
In [1]: import json In [2]: trunk_template = ('switchport trunk encapsulation dot1q', . 'switchport mode trunk', . 'switchport trunk native vlan 999', . 'switchport trunk allowed vlan') In [3]: print(type(trunk_template)) In [4]: with open('trunk_template.json', 'w') as f: . json.dump(trunk_template, f, sort_keys=True, indent=2) . In [5]: cat trunk_template.json [ "switchport trunk encapsulation dot1q", "switchport mode trunk", "switchport trunk native vlan 999", "switchport trunk allowed vlan" ] In [6]: templates = json.load(open('trunk_template.json')) In [7]: type(templates) Out[7]: list In [8]: print(templates) ['switchport trunk encapsulation dot1q', 'switchport mode trunk', 'switchport trunk native vlan 999', 'switchport trunk allowed vlan']
Так происходит из-за того, что в JSON используются другие типы данных и не для всех типов данных Python есть соответствия.
Таблица конвертации данных Python в JSON: