¿Cómo escribo datos JSON en un archivo?

1122

Tengo datos JSON almacenados en la variable data.

Quiero escribir esto en un archivo de texto para probarlo, así no tengo que tomar los datos del servidor cada vez.

Actualmente, estoy intentando esto:

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

Y estoy recibiendo este error:

TypeError: debe ser string o buffer, no dict

¿Cómo arreglar esto?

usuario1530318
fuente

Respuestas:

2042

Olvidó la parte real de JSON: data es un diccionario y aún no está codificado con JSON. Escríbalo así para obtener la máxima compatibilidad (Python 2 y 3):

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

En un sistema moderno (es decir, soporte para Python 3 y UTF-8), puede escribir un archivo más agradable con

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)
phihag
fuente
8
esto podría ser útil para la serialización: stackoverflow.com/questions/4512982/…
jedierikb
12
¿Te refieres a json.dump o json.dumps?
TerminalDilettante
153
@TerminalDilettante json.dumpescribe en un archivo u objeto similar a un archivo, mientras que json.dumpsdevuelve una cadena.
phihag
24
por cierto: para volver a leer el uso de datos: con open ('data.txt') como infile: d = json.load (infile). Ver: esta respuesta
klaas
99
@denvar No, esta respuesta está finamente ajustada. En Python 3, json.dumpescribe en un archivo de texto, no en un archivo binario. Obtendría un TypeErrorsi el archivo se abrió con wb. En versiones anteriores de Python, ambos funcionan wy wbfuncionan. No es necesaria una codificación explícita ya que la salida de json.dumpes solo ASCII por defecto. Si puede estar seguro de que su código nunca se ejecuta en versiones heredadas de Python y usted y el controlador del archivo JSON pueden manejar correctamente datos que no son ASCII, puede especificar uno y configurarlo ensure_ascii=False.
phihag
267

Para obtener utf8 -encoded file en lugar de ascii -encoded en la respuesta aceptada para 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))

El código es más simple en Python 3:

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

En Windows, el encoding='utf-8'argumento paraopen sigue siendo necesario.

Para evitar almacenar una copia codificada de los datos en la memoria (resultado de dumps) y generar cadenas de bytes codificadas por utf8 en Python 2 y 3, use:

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

La codecs.getwriterllamada es redundante en Python 3 pero se requiere para Python 2


Legibilidad y tamaño:

El uso de ensure_ascii=Falseda una mejor legibilidad y un tamaño más pequeño:

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

Mejore aún más la legibilidad agregando banderas indent=4, sort_keys=True(como lo sugiere dinos66 ) a los argumentos de dumpo dumps. De esta forma, obtendrá una estructura ordenada muy bien sangrada en el archivo json a costa de un tamaño de archivo ligeramente mayor.

Antony Hatchkins
fuente
55
El unicodees superfluo: el resultado de json.dumpsya es un objeto unicode. Tenga en cuenta que esto falla en 3.x, donde todo este desorden del modo de archivo de salida se ha limpiado, y json siempre usa cadenas de caracteres (y E / S de caracteres) y nunca bytes.
phihag
44
En 2.x type(json.dumps('a'))es <type 'str'>. Incluso lo type(json.dumps('a', encoding='utf8'))es <type 'str'>.
Antony Hatchkins
44
Sí, en 3.x json usa cadenas, pero la codificación predeterminada es ascii. Tienes que decirle explícitamente que quieres utf8incluso en 3.x. Se actualizó la respuesta.
Antony Hatchkins
44
Oh, tienes toda la razón. Debo haber confundido algo. +1 para el detalle.
phihag
1
La respuesta de Python 3.x funcionó para mí aunque estoy usando 2.7. La respuesta 2.x devuelve un error: 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). Entonces, cuando tenga dudas, use la respuesta 3.x
Blairg23
162

Yo respondería con una ligera modificación con las respuestas antes mencionadas y eso es escribir un archivo JSON prettificado que los ojos humanos puedan leer mejor. Para esto, pasa sort_keyscomo Truey indentcon 4 caracteres espaciales y listo. También asegúrese de que los códigos ASCII no se escriban en su archivo JSON:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)
ambodi
fuente
2
sigue recibiendoUnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek
1
@SirBenBenji Asegúrese de que la cadena que está intentando escribir siga: str.decode ('utf-8').
ambodi
1
@SirBenBenji También puedes intentar usar códecs, como dinos66 especifica a continuación
Shiv
También debe declarar su codificación agregando # -*- coding: utf-8 -*-después del shebang
aesede
2
+1 para sort_keys y sangrado. @aesede No es bueno agregar esta línea porque dará la impresión de que esta solución también funciona con python2, lo que no funciona ( UnicodeEncodeErrorcon datos no ASCII). Vea mi solución para más detalles.
Antony Hatchkins
111

Leer y escribir archivos JSON con Python 2 + 3; trabaja con 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)

Explicación de los parámetros de json.dump:

  • indent: Use 4 espacios para sangrar cada entrada, por ejemplo, cuando se inicia un nuevo dict (de lo contrario, todos estarán en una línea),
  • sort_keys: ordena las claves de los diccionarios. Esto es útil si desea comparar archivos json con una herramienta diff / ponerlos bajo control de versiones.
  • separators: Para evitar que Python agregue espacios en blanco al final

Con un paquete

Eche un vistazo a mi paquete de utilidades mpupara encontrar uno súper simple y fácil de recordar:

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

Archivo JSON creado

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

Finales de archivo comunes

.json

Alternativas

Para su aplicación, lo siguiente puede ser importante:

  • Soporte por otros lenguajes de programación.
  • Rendimiento de lectura / escritura
  • Compacidad (tamaño del archivo)

Ver también: Comparación de formatos de serialización de datos.

En caso de que esté buscando una forma de crear archivos de configuración, puede leer mi breve artículo Archivos de configuración en Python

Martin Thoma
fuente
2
Tenga en cuenta que la force_asciibandera es Truepor defecto. Tendrá "\u20ac"secuencias de 6 bytes ilegibles para cada una en su archivo json (así como de cualquier otro carácter no ASCII).
Antony Hatchkins
¿Por qué lo usas openpara leer pero io.openpara escribir? ¿Es posible usarlo también io.openpara leer? Si es así, ¿qué parámetros se deben pasar?
Micah Zoltu
23

Para aquellos de ustedes que están tratando de deshacerse del griego u otros lenguajes "exóticos" como yo, pero también están teniendo problemas (errores unicode) con caracteres extraños como el símbolo de paz (\ u262E) u otros que a menudo están contenidos en datos formateados json como Twitter, la solución podría ser la siguiente (sort_keys es 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
fuente
1
1 Mientras docs recomienda incorporado python3 openy la assotiated io.openmás codecs.open, en este caso también es un truco compatible hacia atrás agradables. En python2 codecs.openes más "omnívoro" que io.open (puede "comer" tanto str como unicode, convirtiendo si es necesario). Se puede decir que este codecs.opencapricho compensa el json.dumpscapricho de generar diferentes tipos de objetos ( str/ unicode) dependiendo de la presencia de las cadenas unicode en la entrada.
Antony Hatchkins
10

No tengo suficiente reputación para agregar comentarios, así que solo escribo algunos de mis hallazgos de este molesto TypeError aquí:

Básicamente, creo que es un error en la json.dump()función solo en Python 2 : no puede volcar datos de Python (diccionario / lista) que contienen caracteres no ASCII, incluso si abre el archivo con el encoding = 'utf-8'parámetro. (es decir, no importa lo que hagas). Pero, json.dumps()funciona tanto en Python 2 como en 3.

Para ilustrar esto, siguiendo la respuesta de phihag: el código en su respuesta se rompe en Python 2 con excepción TypeError: must be unicode, not str, si datacontiene caracteres no 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)

Sin embargo, funciona bien en Python 3.

ibic
fuente
Explique razones cuando afirma que algo está mal. Use @nickname para que la persona sea notificada. No puede escribir comentarios, pero puede leer comentarios. Como ya dije en mi respuesta al primer comentario, inténtalo data = {'asdf': 1}. Obtendrá la notoria TypeErrorcon su (segunda) variante.
Antony Hatchkins
En cuanto a ensure_ascii- es necesario si desea obtener una salida utf8 "real". Sin ella, tendrá un ascii simple con 6 bytes por letra rusa en lugar de 2 bytes por carácter con esta bandera.
Antony Hatchkins
@AntonyHatchkins Tienes razón para el unicode()papel. Me acabo de dar cuenta de iopaquete en Python 2, write()las necesidades unicode, no str.
ibic
1
Este código funciona para mí incluso con python2.6.6, Debian (10 de diciembre de 2010). Así como con python2.7.9 o python3. Compruébalo una vez más, por favor.
Antony Hatchkins
7

Escriba un dato en el archivo usando JSON use json.dump () o json.dumps () usado. escribir así para almacenar datos en el archivo.

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

Este ejemplo en la lista se almacena en un archivo.

Vishal Gediya
fuente
es similar pero proporciona un ejemplo
Vishal Gediya
5

Para escribir el JSON con sangría, "impresión bonita":

import json

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

Además, si necesita depurar JSON con formato incorrecto y desea un mensaje de error útil, use la import simplejsonbiblioteca en lugar de import json(las funciones deben ser las mismas)

James Wierzba
fuente
4
json.dump(data, open('data.txt', 'wb'))
Alejandro
fuente
2
Esto hace lo mismo que la respuesta de @ phihag, pero no se garantiza que funcione en todo momento. Considere dicho código: f = open('1.txt', 'w'); f.write('a'); input(). Ejecútelo y luego SYGTERM ( Ctrl-Zluego kill %1en Linux, Ctrl-Breaken Windows). 1.txttendrá 0 bytes. Esto se debe a que la escritura se almacenó en el búfer y no se cerró el archivo ni se cerró en el momento en que se produjo SYGTERM. withEl bloque garantiza que el archivo siempre se cierre al igual que el bloque 'probar / finalmente', pero más corto.
Antony Hatchkins
3

Escribir JSON en un archivo

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)

Leer JSON desde un archivo

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
fuente
Bienvenido a Stack Overflow. Si decide responder una pregunta anterior que tiene respuestas bien establecidas y correctas, agregar una nueva respuesta al final del día puede no darle ningún crédito. Si tiene alguna información nueva distintiva, o si está convencido de que las otras respuestas son incorrectas, agregue una nueva respuesta, pero 'otra respuesta' que proporciona la misma información básica mucho tiempo después de que se formuló la pregunta generalmente gana ' No te ganaré mucho crédito. (Muestra algunos datos de muestra; eso es bueno, pero no estoy seguro de que sea suficiente, especialmente porque no muestra lo que se produce para los datos de muestra.)
Jonathan Leffler
Ok, gracias por la orientación
Iman
2

si está intentando escribir un marco de datos de pandas en un archivo usando un formato json, recomendaría esto

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

Todas las respuestas anteriores son correctas. Aquí hay un ejemplo muy simple:

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

ingrese la descripción de la imagen aquí

grepit
fuente
1

La respuesta aceptada está bien. Sin embargo, me encontré con el error "no es serializable json" al usar eso.

Así es como lo arreglé open("file-name.json", 'w')como salida:

output.write(str(response))

Aunque no es una buena solución, ya que el archivo json que crea no tendrá comillas dobles, sin embargo, es excelente si está buscando algo rápido y sucio.

Akshat Bajaj
fuente
0

Los datos JSON se pueden escribir en un archivo de la siguiente manera

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

Escribe en un archivo:

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