Как мне записать данные JSON в файл?


1123

У меня есть данные JSON, хранящиеся в переменной data.

Я хочу записать это в текстовый файл для тестирования, чтобы мне не приходилось каждый раз получать данные с сервера.

В настоящее время я пытаюсь это:

obj = open('data.txt', 'wb')
obj.write(data)
obj.close

И я получаю эту ошибку:

Ошибка типа: должна быть строкой или буфером, а не dict

Как это исправить?

Ответы:


2042

Вы забыли фактическую часть JSON - dataэто словарь, но еще не закодированный в формате JSON. Напишите это для максимальной совместимости (Python 2 и 3):

import json
with open('data.json', 'w') as f:
    json.dump(data, f)

В современной системе (т.е. поддержка Python 3 и UTF-8) вы можете написать более приятный файл с

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

8
это может быть полезно для сериализации: stackoverflow.com/questions/4512982/…
jedierikb

12
Вы имеете в виду json.dump или json.dumps?
TerminalDilettante

153
@TerminalDilettante json.dumpзаписывает в файл или подобный файлу объект, тогда как json.dumpsвозвращает строку.
Phihag

24
btw: чтобы перечитать данные, используйте: с open ('data.txt') как infile: d = json.load (infile). Смотрите: этот ответ
Клаас

9
@denvar Нет, этот ответ точно настроен. На Python 3 json.dumpпишет в текстовый файл, а не в двоичный файл. Вы получите, TypeErrorесли файл был открыт с wb. В более старых версиях Python работают как wnand , так и другие wb. Явное кодирование не требуется, так как вывод json.dumpпо умолчанию только для ASCII. Если вы можете быть уверены, что ваш код никогда не запускается на устаревших версиях Python, и вы и обработчик файла JSON можете правильно обрабатывать данные, не относящиеся к ASCII, вы можете указать их и установить ensure_ascii=False.
phihag

267

Чтобы получить файл с кодировкой utf8, а не кодированный ascii в принятом ответе для Python 2, используйте:

import io, json
with io.open('data.txt', 'w', encoding='utf-8') as f:
  f.write(json.dumps(data, ensure_ascii=False))

Код проще в Python 3:

import json
with open('data.txt', 'w') as f:
  json.dump(data, f, ensure_ascii=False)

В Windows encoding='utf-8'аргумент to openпо-прежнему необходим.

Чтобы не хранить зашифрованную копию данных в памяти (результат dumps) и выводить строки кодирования utf8 в Python 2 и 3, используйте:

import json, codecs
with open('data.txt', 'wb') as f:
    json.dump(data, codecs.getwriter('utf-8')(f), ensure_ascii=False)

codecs.getwriterВызов является излишним в Python 3 , но требуется для Python 2


Читаемость и размер:

Использование ensure_ascii=Falseдает лучшую читаемость и меньший размер:

>>> json.dumps({'price': '€10'})
'{"price": "\\u20ac10"}'
>>> json.dumps({'price': '€10'}, ensure_ascii=False)
'{"price": "€10"}'

>>> len(json.dumps({'абвгд': 1}))
37
>>> len(json.dumps({'абвгд': 1}, ensure_ascii=False).encode('utf8'))
17

Дальнейшее улучшение читабельности путем добавления флагов indent=4, sort_keys=True(как предложено dinos66 ) к аргументам dumpили dumps. Таким образом, вы получите аккуратно отсортированную структуру с отступом в файле json за счет немного большего размера файла.


5
Это unicodeлишнее - результат json.dumpsуже является объектом Unicode. Обратите внимание, что это не работает в 3.x, где весь этот беспорядок режима выходного файла был очищен, и json всегда использует символьные строки (и символьный ввод / вывод) и никогда не байты.
phihag

4
В 2.х type(json.dumps('a'))есть <type 'str'>. Даже type(json.dumps('a', encoding='utf8'))есть <type 'str'>.
Энтони Хэтчкинс

4
Да, в 3.x json использует строки, но кодировкой по умолчанию является ascii. Вы должны явно сказать, что вы хотите utf8даже в 3.x. Обновил ответ.
Энтони Хэтчкинс

4
О, вы совершенно правы - должно быть, я что-то напутал. +1 за детали.
phihag

1
Ответ Python 3.x работал для меня, хотя я использую 2.7. 2.x ответ возвратил ошибку: 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). Поэтому, если вы сомневаетесь, используйте ответ 3.x!
Blairg23

162

Я бы ответил с небольшими изменениями с вышеупомянутыми ответами, а именно, чтобы написать предварительно подтвержденный файл JSON, который человеческие глаза могут читать лучше. Для этого передайте sort_keysкак Trueи indentс 4 пробелами, и все готово. Также позаботьтесь о том, чтобы коды ascii не были записаны в вашем файле JSON:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)

2
все еще получаюUnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek

1
@SirBenBenji Убедитесь, что строка, которую вы пытаетесь написать, должна следовать: str.decode ('utf-8').
Амбоди

1
@SirBenBenji Вы также можете попробовать использовать кодеки, как указано в dinos66 ниже
Shiv

Вы также должны объявить свою кодировку, добавив # -*- coding: utf-8 -*-после shebang
aesede

2
+1 для sort_keys и отступа. @aesede Не стоит добавлять эту строку, потому что у вас сложится впечатление, что это решение работает и с python2, что не работает ( UnicodeEncodeErrorс данными, отличными от ascii). Смотрите мое решение для деталей.
Энтони Хэтчкинс

111

Чтение и запись файлов JSON с помощью Python 2 + 3; работает с юникодом

# -*- coding: utf-8 -*-
import json

# Make it work for Python 2+3 and with Unicode
import io
try:
    to_unicode = unicode
except NameError:
    to_unicode = str

# Define data
data = {'a list': [1, 42, 3.141, 1337, 'help', u'€'],
        'a string': 'bla',
        'another dict': {'foo': 'bar',
                         'key': 'value',
                         'the answer': 42}}

# Write JSON file
with io.open('data.json', 'w', encoding='utf8') as outfile:
    str_ = json.dumps(data,
                      indent=4, sort_keys=True,
                      separators=(',', ': '), ensure_ascii=False)
    outfile.write(to_unicode(str_))

# Read JSON file
with open('data.json') as data_file:
    data_loaded = json.load(data_file)

print(data == data_loaded)

Объяснение параметров json.dump:

  • indent: Используйте 4 пробела для отступа каждой записи, например, когда начинается новый dict (иначе все будут в одной строке),
  • sort_keys: сортировка ключей словарей. Это полезно, если вы хотите сравнить файлы json с помощью инструмента сравнения / поставить их под контроль версий.
  • separators: Запретить Python добавлять конечные пробелы

С пакетом

Взгляните на мой пакет утилит mpuдля супер простого и легко запоминающегося:

import mpu.io
data = mpu.io.read('example.json')
mpu.io.write('example.json', data)

Создан файл JSON

{
    "a list":[
        1,
        42,
        3.141,
        1337,
        "help",
        "€"
    ],
    "a string":"bla",
    "another dict":{
        "foo":"bar",
        "key":"value",
        "the answer":42
    }
}

Общие окончания файлов

.json

альтернативы

Для вашего приложения может быть важно следующее:

  • Поддержка другими языками программирования
  • Чтение / запись производительности
  • Компактность (размер файла)

Смотрите также: Сравнение форматов сериализации данных

Если вы предпочитаете создавать файлы конфигурации, вы можете прочитать мою короткую статью Файлы конфигурации в Python


2
Обратите внимание, что force_asciiфлаг установлен Trueпо умолчанию. Вы будете иметь нечитаемые 6-байтовые "\u20ac"последовательности для каждого в вашем json-файле (а также любого другого не-ascii символа).
Энтони Хэтчкинс

Почему вы используете openдля чтения, но io.openдля письма? Это можно использовать io.openдля чтения, а? Если это так, какие параметры должны быть переданы?
Мика Золту

23

Для тех из вас, кто пытается избавиться от греческого или других «экзотических» языков, таких как я, но также имеет проблемы (ошибки Юникода) со странными символами, такими как символ мира (\ u262E) или другими, которые часто содержатся в данных, отформатированных в json например, Twitter, решение может быть следующим (sort_keys явно необязателен):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))

1
+1 Хотя документы рекомендует python3 встроенную команду openи assotiated io.openнад codecs.open, в данном случае это также хороший обратной совместимости хак. В python2 codecs.openболее «всеяден», чем io.open (он может «съесть» как str, так и unicode, конвертируя при необходимости). Можно сказать, что эта codecs.openпричуда компенсирует json.dumpsпричуду генерации различных типов объектов ( str/ unicode) в зависимости от наличия строк ввода Unicode на входе.
Энтони Хэтчкинс

10

У меня недостаточно репутации, чтобы добавлять комментарии, поэтому я просто напишу некоторые из своих выводов об этой надоедливой ошибке TypeError здесь:

По сути, я думаю, что это ошибка в json.dump()функции только в Python 2 - она ​​не может вывести данные Python (словарь / список), содержащие не-ASCII символы, даже если вы открываете файл с encoding = 'utf-8'параметром. (т.е. независимо от того, что вы делаете). Но json.dumps()работает на Python 2 и 3.

Чтобы проиллюстрировать это, проследим за ответом phihag: код в его ответе разбивается на Python 2 за исключением TypeError: must be unicode, not str, если он dataсодержит символы не ASCII. (Python 2.7.6, Debian):

import json
data = {u'\u0430\u0431\u0432\u0433\u0434': 1} #{u'абвгд': 1}
with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

Тем не менее, он отлично работает в Python 3.


Укажите причины, когда вы заявляете, что что-то не так. Используйте @nickname, чтобы человек получал уведомления. Вы не можете писать комментарии, но вы можете читать комментарии. Как уже говорилось в моем ответе на первый комментарий, попробуйте data = {'asdf': 1}. Вы получите пресловутый TypeErrorс вашим (вторым) вариантом.
Энтони Хэтчкинс

По поводу ensure_ascii- это необходимо, если вы хотите получить "настоящий" вывод utf8. Без этого у вас будет простой ascii с 6 байтами на русскую букву, а не 2 байта на символ с этим флагом.
Энтони Хэтчкинс

@AntonyHatchkins Вы правы на unicode()часть. Я только что понял для ioпакета в Python 2, write()нуждается unicode, а не str.
ibic

1
Этот код работает для меня даже с python2.6.6, Debian (10 декабря 2010). Как и с python2.7.9 или python3. Проверьте это еще раз, плз.
Энтони Хэтчкинс

7

Запишите данные в файл, используя JSON, используя json.dump () или json.dumps () . напишите так, чтобы сохранить данные в файле.

import json
data = [1,2,3,4,5]
with open('no.txt', 'w') as txtfile:
    json.dump(data, txtfile)

этот пример в списке хранится в файл.


это похоже, но
приведу

5

Чтобы написать JSON с отступом "pretty print":

import json

outfile = open('data.json')
json.dump(data, outfile, indent=4)

Кроме того, если вам нужно отладить неправильно отформатированный JSON и получить полезное сообщение об ошибке, используйте import simplejsonбиблиотеку вместо import json(функции должны быть такими же)


4
json.dump(data, open('data.txt', 'wb'))

2
Это делает то же самое, что и ответ @ phihag, но не всегда работает. Рассмотрим такой код: f = open('1.txt', 'w'); f.write('a'); input(). Запустите его, а затем SYGTERM ( Ctrl-Zзатем kill %1в Linux, Ctrl-Breakв Windows). 1.txtбудет иметь 0 байтов. Это связано с тем, что запись была буферизована, а файл не был ни сброшен, ни закрыт в момент возникновения SYGTERM.withБлок гарантирует, что файл всегда будет закрыт так же, как блок «try / finally», но короче.
Энтони Хэтчкинс

3

Запись JSON в файл

import json

data = {}
data['people'] = []
data['people'].append({
    'name': 'Scott',
    'website': 'stackabuse.com',
    'from': 'Nebraska'
})
data['people'].append({
    'name': 'Larry',
    'website': 'google.com',
    'from': 'Michigan'
})
data['people'].append({
    'name': 'Tim',
    'website': 'apple.com',
    'from': 'Alabama'
})

with open('data.txt', 'w') as outfile:
    json.dump(data, outfile)

Чтение 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('')

Добро пожаловать в стек переполнения. Если вы решите ответить на более старый вопрос, на котором уже есть точные и правильные ответы, добавление нового ответа в конце дня может не принести вам никакой пользы. Если у вас есть какая-то отличительная новая информация, или вы убеждены, что все остальные ответы неверны, обязательно добавьте новый ответ, но «еще один ответ», дающий ту же основную информацию спустя долгое время после того, как вопрос был задан, обычно выигрывает ». Я не заработаю тебе много кредитов. (Вы показываете некоторые данные примера; это хорошо, но я не уверен, что этого достаточно, особенно потому, что вы не показываете, что производится для данных образца.)
Джонатан Леффлер

Ok спасибо за инструктивный
имана

2

если вы пытаетесь записать pandas dataframe в файл в формате json, я бы порекомендовал это

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()

2

Все предыдущие ответы верны, вот очень простой пример:

#! /usr/bin/env python
import json

def write_json():
    # create a dictionary  
    student_data = {"students":[]}
    #create a list
    data_holder = student_data["students"]
    # just a counter
    counter = 0
    #loop through if you have multiple items..         
    while counter < 3:
        data_holder.append({'id':counter})
        data_holder.append({'room':counter})
        counter += 1    
    #write the file        
    file_path='/tmp/student_data.json'
    with open(file_path, 'w') as outfile:
        print("writing file to: ",file_path)
        # HERE IS WHERE THE MAGIC HAPPENS 
        json.dump(student_data, outfile)
    outfile.close()     
    print("done")

write_json()

введите описание изображения здесь


1

Принятый ответ в порядке. Тем не менее, я столкнулся с ошибкой "не json serializable", используя это.

Вот как я исправил это open("file-name.json", 'w')как вывод:

output.write(str(response))

Хотя это не очень удачное решение, так как создаваемый файл json не будет иметь двойных кавычек, однако это хорошо, если вы ищете быстрый и грязный.


0

Данные JSON могут быть записаны в файл следующим образом

hist1 = [{'val_loss': [0.5139984398465246],
'val_acc': [0.8002029867684085],
'loss': [0.593220705309384],
'acc': [0.7687131817929321]},
{'val_loss': [0.46456472964199463],
'val_acc': [0.8173602046780344],
'loss': [0.4932038113037539],
'acc': [0.8063946213802453]}]

Написать в файл:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.