Como gravar dados JSON em um arquivo?

1122

Eu tenho dados JSON armazenados na variável data.

Quero gravar isso em um arquivo de texto para teste, para que não precise pegar os dados do servidor todas as vezes.

Atualmente, estou tentando o seguinte:

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

E estou recebendo este erro:

TypeError: deve ser string ou buffer, não dict

Como consertar isto?

user1530318
fonte

Respostas:

2041

Você esqueceu a parte JSON real - dataé um dicionário e ainda não está codificado em JSON. Escreva assim para obter compatibilidade máxima (Python 2 e 3):

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

Em um sistema moderno (por exemplo, suporte ao Python 3 e UTF-8), você pode escrever um arquivo melhor com

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)
phihag
fonte
8
isso pode ser útil para a serialização: stackoverflow.com/questions/4512982/...
jedierikb
12
Você quer dizer json.dump ou json.dumps?
TerminalDilettante
153
@TerminalDilettante json.dumpgrava em um arquivo ou objeto semelhante a um arquivo, enquanto json.dumpsretorna uma string.
Phihag 13/08/2015
24
btw: para reler os dados use: with open ('data.txt') como infile: d = json.load (infile). Veja: essa resposta
Klaas
9
@denvar Não, esta resposta está afinada. No Python 3, json.dumpgrava em um arquivo de texto, não em um arquivo binário. Você receberia um TypeErrorse o arquivo fosse aberto com wb. Em versões mais antigas do Python, tanto wne wbtrabalho. Uma codificação explícita não é necessária, pois a saída de json.dumpé apenas ASCII por padrão. Se você pode ter certeza de que seu código nunca é executado nas versões herdadas do Python e você e o manipulador do arquivo JSON podem manipular corretamente dados não ASCII, você pode especificar um e definir ensure_ascii=False.
Phihag 19/04/19
267

Para obter o arquivo codificado em utf8 em vez de codificado em ascii na resposta aceita para o Python 2, use:

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

O código é mais simples no Python 3:

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

No Windows, o encoding='utf-8'argumento para openainda é necessário.

Para evitar o armazenamento de uma cópia codificada dos dados na memória (resultado de dumps) e a saída de seqüências de caracteres codificadas em utf8 no Python 2 e 3, use:

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

A codecs.getwriterchamada é redundante no Python 3, mas necessária para o Python 2


Legibilidade e tamanho:

O uso de ensure_ascii=Falsefornece melhor legibilidade e tamanho menor:

>>> 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

Melhore ainda mais a legibilidade adicionando sinalizadores indent=4, sort_keys=True(como sugerido por dinos66 ) aos argumentos de dumpou dumps. Dessa forma, você obterá uma estrutura ordenada bem recuada no arquivo json ao custo de um tamanho de arquivo um pouco maior.

Antony Hatchkins
fonte
5
O unicodeé supérfluo - o resultado de json.dumpsjá é um objeto unicode. Observe que isso falha no 3.x, onde toda essa bagunça do modo de arquivo de saída foi limpa, e o json sempre usa cadeias de caracteres (e E / S de caracteres) e nunca bytes.
phihag
4
Em 2.x type(json.dumps('a'))é <type 'str'>. Even type(json.dumps('a', encoding='utf8'))is <type 'str'>.
Antony Hatchkins
4
Sim, no 3.x, o json usa strings, mas a codificação padrão é ascii. Você precisa explicitamente dizer que deseja utf8mesmo no 3.x. Atualizado a resposta.
Antony Hatchkins
4
Oh, você está totalmente certo - devo ter confundido alguma coisa. +1 para os detalhes.
phihag
1
A resposta do Python 3.x funcionou para mim, embora eu esteja usando o 2.7. A resposta 2.x retornou um erro: 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). Portanto, quando estiver em dúvida, use a resposta 3.x!
Blairg23
162

Eu responderia com ligeiras modificações com as respostas acima mencionadas e isso é para escrever um arquivo JSON prettificado que os olhos humanos possam ler melhor. Para isso, passe sort_keyscomo Truee indentcom 4 caracteres de espaço e você estará pronto. Também verifique se os códigos ascii não serão gravados no seu arquivo JSON:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)
ambodi
fonte
2
Ainda está recebendo #UnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek
1
@SirBenBenji Verifique se a sequência que você está tentando escrever segue: str.decode ('utf-8').
ambodi
1
@SirBenBenji Você também pode tentar usar codecs, como dinos66 especifica abaixo
Shiv
Você também tem que declarar a sua codificação, acrescentando # -*- coding: utf-8 -*-após o shebang
aesede
2
+1 para sort_keys e recuo. @ aesede Não é bom adicionar essa linha, pois ficará com a impressão de que essa solução funciona com python2, o que não acontece ( UnicodeEncodeErrorcom dados não-ascii). Veja minha solução para detalhes.
Antony Hatchkins
111

Leia e grave arquivos JSON com Python 2 + 3; trabalha com unicode

# -*- 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)

Explicação dos parâmetros de json.dump:

  • indent: Use 4 espaços para recuar cada entrada, por exemplo, quando um novo ditado é iniciado (caso contrário, todos estarão em uma linha),
  • sort_keys: classifica as chaves dos dicionários. Isso é útil se você deseja comparar arquivos json com uma ferramenta diff / colocá-los sob controle de versão.
  • separators: Para impedir que o Python adicione espaços em branco à direita

Com um pacote

Dê uma olhada no meu pacote de utilitários mpupara obter um super simples e fácil de lembrar:

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

Arquivo JSON criado

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

Finais de arquivos comuns

.json

Alternativas

Para seu aplicativo, o seguinte pode ser importante:

  • Suporte por outras linguagens de programação
  • Desempenho de leitura / escrita
  • Compacidade (tamanho do arquivo)

Consulte também: Comparação de formatos de serialização de dados

Caso você esteja procurando uma maneira de criar arquivos de configuração, leia meu pequeno artigo Arquivos de configuração em Python

Martin Thoma
fonte
2
Observe que o force_asciisinalizador é Truepor padrão. Você terá "\u20ac"sequências ilegíveis de 6 bytes para cada arquivo json (assim como qualquer outro caractere não-ascii).
Antony Hatchkins
Por que você usa openpara a leitura, mas io.openpara escrever? Também é possível usar io.openpara leitura? Se sim, quais parâmetros devem ser passados?
Micah Zoltu
23

Para aqueles que estão tentando despejar grego ou outras línguas "exóticas", como eu, mas também estão tendo problemas (erros unicode) com caracteres estranhos, como o símbolo de paz (\ u262E) ou outros que geralmente estão contidos em dados formatados por json como no Twitter, a solução pode ser a seguinte (sort_keys é obviamente opcional):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))
dinos66
fonte
1
+1 Enquanto docs recomenda python3 builtin openeo assotiated io.openmais codecs.open, neste caso, também é um hack agradáveis compatível com versões anteriores. Em python2 codecs.opené mais "onívoro" que io.open (pode "comer" str e unicode, convertendo se necessário). Pode-se dizer que essa codecs.openpeculiaridade compensa a json.dumpspeculiaridade de gerar diferentes tipos de objetos ( str/ unicode) dependendo da presença das cadeias unicode na entrada.
Antony Hatchkins
10

Como não tenho reputação suficiente para adicionar comentários, escrevo aqui algumas das minhas descobertas sobre este TypeError irritante:

Basicamente, acho que é um bug na json.dump()função somente no Python 2 - ele não pode despejar dados do Python (dicionário / lista) contendo caracteres não ASCII, mesmo que você abra o arquivo com o encoding = 'utf-8'parâmetro (ou seja, não importa o que você faça). Mas, json.dumps()funciona em Python 2 e 3.

Para ilustrar isso, acompanhando a resposta de phihag: o código em sua resposta quebra no Python 2 com exceção TypeError: must be unicode, not str, se datacontiver caracteres não 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)

No entanto, funciona bem em Python 3.

ibic
fonte
Dê razões quando afirma que algo está errado. Use @nickname para que a pessoa seja notificada. Você não pode escrever comentários, mas pode ler comentários. Como já indicado na minha resposta ao primeiro comentário, tente data = {'asdf': 1}. Você obterá o notório TypeErrorcom sua (segunda) variante.
Antony Hatchkins
No ensure_asciique diz respeito - é necessário se você deseja obter uma saída utf8 "real". Sem ele, você terá ascii simples com 6 bytes por letra russa, em vez de 2 bytes por caractere com esse sinalizador.
Antony Hatchkins
@AntonyHatchkins Você está certo para a unicode()parte. Acabei de perceber para o iopacote em Python 2, write()necessidades unicode, não str.
ibic 12/02
1
Este código funciona para mim mesmo com python2.6.6, Debian (10 de dezembro de 2010). Assim como no python2.7.9 ou python3. Verifique mais uma vez, plz.
Antony Hatchkins
7

Grave dados no arquivo usando JSON, use json.dump () ou json.dumps () usado. escreva assim para armazenar dados em arquivo.

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

este exemplo na lista é armazenado em um arquivo.

Vishal Gediya
fonte
é semelhante, mas com exemplo
Vishal Gediya
5

Para escrever o JSON com recuo, "pretty print":

import json

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

Além disso, se você precisar depurar JSON formatado incorretamente e desejar uma mensagem de erro útil, use a import simplejsonbiblioteca, em vez de import json(as funções devem ser as mesmas)

James Wierzba
fonte
4
json.dump(data, open('data.txt', 'wb'))
Alexander
fonte
2
Isso faz o mesmo que a resposta de @ phihag, mas não é garantido que funcione o tempo todo. Considere esse código: f = open('1.txt', 'w'); f.write('a'); input(). Execute-o e depois SYGTERM-lo ( Ctrl-Zdepois kill %1no Linux, Ctrl-Breakno Windows). 1.txtterá 0 bytes. Isso ocorre porque a gravação foi armazenada em buffer e o arquivo não foi liberado e não foi fechado no momento em que ocorreu o SYGTERM. withO bloco garante que o arquivo sempre seja fechado da mesma forma que o bloco 'try / finally', mas menor.
Antony Hatchkins
3

Gravando JSON em um arquivo

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)

Lendo JSON de um arquivo

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('')
iman
fonte
Bem-vindo ao Stack Overflow. Se você decidir responder a uma pergunta antiga que tenha respostas bem estabelecidas e corretas, adicionar uma nova resposta no final do dia pode não lhe dar crédito. Se você tiver alguma informação nova e distinta, ou estiver convencido de que as outras respostas estão erradas, adicione uma nova resposta, mas "mais uma resposta" fornecerá a mesma informação básica muito tempo depois que a pergunta for feita normalmente " você ganha muito crédito. (Você mostra alguns dados da amostra, que é boa, mas eu não tenho certeza que é o suficiente, especialmente porque você não mostrar o que é produzido para os dados de exemplo.)
Jonathan Leffler
Ok, obrigado pela orientação.
iman
2

se você estiver tentando gravar um dataframe do pandas em um arquivo usando o formato json, eu recomendaria isso

destination='filepath'
saveFile = open(destination, 'w')
saveFile.write(df.to_json())
saveFile.close()
Franco Miguel Contreras
fonte
2

Todas as respostas anteriores estão corretas aqui é um exemplo muito simples:

#! /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()

insira a descrição da imagem aqui

grepit
fonte
1

A resposta aceita é boa. No entanto, eu encontrei o erro "não é json serializable" usando isso.

Aqui está como eu o consertei open("file-name.json", 'w')como saída:

output.write(str(response))

Embora não seja uma boa solução, o arquivo json que ele cria não terá aspas duplas, mas é ótimo se você estiver procurando rápido e sujo.

Akshat Bajaj
fonte
0

Os dados JSON podem ser gravados em um arquivo da seguinte maneira

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]}]

Escreva em um arquivo:

with open('text1.json', 'w') as f:
     json.dump(hist1, f)
Ashok Kumar Jayaraman
fonte