Comment écrire des données JSON dans un fichier?

1123

J'ai des données JSON stockées dans la variable data.

Je veux écrire ceci dans un fichier texte pour le test, donc je n'ai pas à récupérer les données du serveur à chaque fois.

Actuellement, j'essaye ceci:

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

Et je reçois cette erreur:

TypeError: doit être une chaîne ou un tampon, pas dict

Comment régler ceci?

user1530318
la source

Réponses:

2042

Vous avez oublié la partie JSON réelle - dataest un dictionnaire et pas encore codé JSON. Écrivez-le comme ceci pour une compatibilité maximale (Python 2 et 3):

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

Sur un système moderne (c'est-à-dire la prise en charge de Python 3 et UTF-8), vous pouvez écrire un fichier plus agréable avec

import json
with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)
phihag
la source
8
cela peut être utile pour la sérialisation: stackoverflow.com/questions/4512982/…
jedierikb
12
Voulez-vous dire json.dump ou json.dumps?
TerminalDilettante
153
@TerminalDilettante json.dumpécrit dans un fichier ou un objet similaire à un fichier, alors qu'il json.dumpsrenvoie une chaîne.
phihag
24
btw: pour relire les données, utilisez: avec open ('data.txt') en tant qu'infile: d = json.load (infile). Voir: cette réponse
klaas
9
@denvar Non, cette réponse est finement réglée. Sur Python 3, json.dumpécrit dans un fichier texte, pas un fichier binaire. Vous obtiendrez un TypeErrorsi le fichier a été ouvert avec wb. Sur les anciennes versions Python, les deux wnand wbtravail. Un codage explicite n'est pas nécessaire car la sortie de json.dumpest uniquement ASCII par défaut. Si vous pouvez être sûr que votre code n'est jamais exécuté sur les versions héritées de Python et que vous et le gestionnaire du fichier JSON pouvez gérer correctement les données non ASCII, vous pouvez en spécifier une et la définir ensure_ascii=False.
phihag
267

Pour obtenir un fichier encodé en utf8 par opposition à encodé en ascii dans la réponse acceptée pour Python 2, utilisez:

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

Le code est plus simple en Python 3:

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

Sous Windows, l' encoding='utf-8'argument to openest toujours nécessaire.

Pour éviter de stocker une copie codée des données en mémoire (résultat de dumps) et pour générer des sous - tests codés en utf8 en Python 2 et 3, utilisez:

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

L' codecs.getwriterappel est redondant en Python 3 mais requis pour Python 2


Lisibilité et taille:

L'utilisation de ensure_ascii=Falsedonne une meilleure lisibilité et une taille plus petite:

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

Améliorez encore la lisibilité en ajoutant des indicateurs indent=4, sort_keys=True(comme suggéré par dinos66 ) aux arguments de dumpou dumps. De cette façon, vous obtiendrez une structure triée bien en retrait dans le fichier json au prix d'une taille de fichier légèrement plus grande.

Antony Hatchkins
la source
5
Le unicodeest superflu - le résultat de json.dumpsest déjà un objet unicode. Notez que cela échoue dans 3.x, où tout le désordre du mode de fichier de sortie a été nettoyé, et json utilise toujours des chaînes de caractères (et des E / S de caractères) et jamais d'octets.
phihag
4
Dans 2.x type(json.dumps('a'))est <type 'str'>. type(json.dumps('a', encoding='utf8'))Est même <type 'str'>.
Antony Hatchkins le
4
Oui, dans 3.x json utilise des chaînes, mais l'encodage par défaut est ascii. Vous devez lui dire explicitement que vous voulez utf8même en 3.x. Mis à jour la réponse.
Antony Hatchkins le
4
Oh, vous avez tout à fait raison - j'ai dû confondre quelque chose. +1 pour le détail.
phihag
1
La réponse Python 3.x a fonctionné pour moi même si j'utilise 2.7. La réponse 2.x a renvoyé une erreur: 'ascii' codec can't decode byte 0xf1 in position 506755: ordinal not in range(128). Alors en cas de doute, utilisez la réponse 3.x!
Blairg23
162

Je répondrais avec une légère modification avec les réponses susmentionnées et c'est d'écrire un fichier JSON prettifié que les yeux humains peuvent mieux lire. Pour cela, passez au sort_keysfur Trueet à mesure indentavec 4 espaces et vous êtes prêt à partir. Veillez également à ce que les codes ascii ne soient pas écrits dans votre fichier JSON:

with open('data.txt', 'w') as outfile:
     json.dump(jsonData, outfile, sort_keys = True, indent = 4,
               ensure_ascii = False)
ambodi
la source
2
toujours obtenirUnicodeEncodeError: 'ascii' codec can't encode character u'\xfc'
stevek
1
@SirBenBenji Assurez-vous que la chaîne que vous essayez d'écrire suit: str.decode ('utf-8').
ambodi
1
@SirBenBenji Vous pouvez également essayer d'utiliser des codecs, comme le précise dinos66 ci
Shiv
Vous devez également déclarer votre encodage en ajoutant # -*- coding: utf-8 -*-après le shebang
aesede
2
+1 pour sort_keys et indent. @aesede Il n'est pas bon d'ajouter cette ligne car cela donnera l'impression que cette solution fonctionne aussi bien avec python2 que ce n'est pas le cas ( UnicodeEncodeErroravec des données non ascii). Voir ma solution pour plus de détails.
Antony Hatchkins
111

Lire et écrire des fichiers JSON avec Python 2 + 3; fonctionne avec 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)

Explication des paramètres de json.dump:

  • indent: Utilisez 4 espaces pour mettre en retrait chaque entrée, par exemple quand un nouveau dict est lancé (sinon tous seront sur une seule ligne),
  • sort_keys: trie les clés des dictionnaires. Ceci est utile si vous souhaitez comparer des fichiers json avec un outil diff / les placer sous contrôle de version.
  • separators: Pour empêcher Python d'ajouter des espaces de fin

Avec un forfait

Jetez un oeil à mon package utilitaire mpupour un super simple et facile à retenir:

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

Fichier JSON créé

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

Terminaisons de fichiers communes

.json

Alternatives

Pour votre application, les éléments suivants peuvent être importants:

  • Prise en charge par d'autres langages de programmation
  • Lecture / écriture
  • Compacité (taille du fichier)

Voir aussi: Comparaison des formats de sérialisation des données

Dans le cas où vous cherchez plutôt un moyen de créer des fichiers de configuration, vous voudrez peut-être lire mon court article Fichiers de configuration en Python

Martin Thoma
la source
2
Notez que l' force_asciiindicateur est Truepar défaut. Vous aurez des "\u20ac"séquences illisibles de 6 octets pour chacune dans votre fichier json (ainsi que pour tout autre caractère non ascii).
Antony Hatchkins
Pourquoi utilisez-vous openpour la lecture mais io.openpour l'écriture? Est-il possible d'utiliser également io.openpour la lecture? Si oui, quels paramètres doivent être transmis?
Micah Zoltu
23

Pour ceux d'entre vous qui essaient de vider le grec ou d'autres langues "exotiques" comme moi, mais qui ont également des problèmes (erreurs unicode) avec des caractères étranges tels que le symbole de paix (\ u262E) ou d'autres qui sont souvent contenus dans des données formatées json comme Twitter, la solution pourrait être la suivante (sort_keys est évidemment optionnel):

import codecs, json
with codecs.open('data.json', 'w', 'utf8') as f:
     f.write(json.dumps(data, sort_keys = True, ensure_ascii=False))
dinos66
la source
1
1 Bien que docs recommande builtin python3 openet assotiated io.openplus codecs.open, dans ce cas , il est aussi une belle entaille rétrocompatible. En python2 codecs.openest plus "omnivore" que io.open (il peut "manger" à la fois str et unicode, en convertissant si nécessaire). On peut dire que cette codecs.openbizarrerie compense la json.dumpsbizarrerie de générer différents types d'objets ( str/ unicode) en fonction de la présence des chaînes unicode en entrée.
Antony Hatchkins
10

Je n'ai pas assez de réputation pour ajouter des commentaires, alors j'écris juste quelques-unes de mes conclusions sur cette TypeError ennuyeuse ici:

Fondamentalement, je pense que c'est un bug dans la json.dump()fonction en Python 2 uniquement - Il ne peut pas vider une donnée Python (dictionnaire / liste) contenant des caractères non ASCII, même si vous ouvrez le fichier avec le encoding = 'utf-8'paramètre. (c'est-à-dire, peu importe ce que vous faites). Mais, json.dumps()fonctionne à la fois sur Python 2 et 3.

Pour illustrer cela, en suivant la réponse de phihag: le code dans sa réponse se casse en Python 2 à l'exception TypeError: must be unicode, not str, s'il datacontient des caractères non 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)

Cela fonctionne cependant très bien en Python 3.

ibic
la source
Donnez des raisons lorsque vous prétendez que quelque chose ne va pas. Utilisez @nickname pour que la personne soit avertie. Vous ne pouvez pas écrire de commentaires, mais vous pouvez lire les commentaires. Comme déjà indiqué dans ma réponse au premier commentaire, essayez data = {'asdf': 1}. Vous obtiendrez le notoire TypeErroravec votre (deuxième) variante.
Antony Hatchkins
Concernant ensure_ascii- c'est nécessaire si vous voulez obtenir une "vraie" sortie utf8. Sans cela, vous aurez un ascii simple avec 6 octets par lettre russe contre 2 octets par caractère avec ce drapeau.
Antony Hatchkins
@AntonyHatchkins Vous avez raison pour la unicode()partie. Je viens de réaliser pour le iopackage en Python 2, les write()besoins unicode, non str.
ibic
1
Ce code fonctionne pour moi même avec python2.6.6, Debian (10 décembre 2010). Ainsi qu'avec python2.7.9 ou python3. Vérifiez encore une fois, plz.
Antony Hatchkins
7

Écrivez une donnée dans un fichier en utilisant JSON utilisez json.dump () ou json.dumps () utilisé. écrire comme ceci pour stocker des données dans un fichier.

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

cet exemple dans la liste est stocké dans un fichier.

Vishal Gediya
la source
c'est similaire mais donnez l'exemple
Vishal Gediya
5

Pour écrire le JSON avec indentation, "pretty print":

import json

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

De plus, si vous devez déboguer un JSON mal formaté et que vous souhaitez un message d'erreur utile, utilisez la import simplejsonbibliothèque au lieu de import json(les fonctions doivent être les mêmes)

James Wierzba
la source
4
json.dump(data, open('data.txt', 'wb'))
Alexandre
la source
2
Cela fait la même chose que la réponse de @ phihag, mais n'est pas garanti de fonctionner à tout moment. Considérez ce code: f = open('1.txt', 'w'); f.write('a'); input(). Exécutez-le puis SYGTERM ( Ctrl-Zpuis kill %1sous linux, Ctrl-Breaksous Windows). 1.txtaura 0 octets. C'est parce que l'écriture a été mise en mémoire tampon et que le fichier n'a été ni vidé ni fermé au moment où SYGTERM s'est produit. withblock garantit que le fichier est toujours fermé comme le fait le bloc 'try / finally' mais plus court.
Antony Hatchkins
3

Écriture de JSON dans un fichier

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)

Lecture de JSON à partir d'un fichier

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
la source
Bienvenue dans Stack Overflow. Si vous décidez de répondre à une question plus ancienne qui a des réponses bien établies et correctes, l'ajout d'une nouvelle réponse en fin de journée peut ne pas vous valoir de crédit. Si vous avez de nouvelles informations distinctives, ou si vous êtes convaincu que les autres réponses sont toutes fausses, ajoutez certainement une nouvelle réponse, mais `` encore une autre réponse '' donnant les mêmes informations de base longtemps après que la question a été posée est généralement gagnée '' t vous gagner beaucoup de crédit. (Vous montrez quelques exemples de données; c'est bien, mais je ne suis pas sûr que ce soit suffisant, d'autant plus que vous ne montrez pas ce qui est produit pour les données d'exemple.)
Jonathan Leffler
Ok merci pour les conseils
iman
2

si vous essayez d'écrire une trame de données pandas dans un fichier en utilisant un format json je recommanderais ceci

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

Toutes les réponses précédentes sont correctes, voici un exemple très 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()

entrez la description de l'image ici

grepit
la source
1

La réponse acceptée est correcte. Cependant, j'ai rencontré une erreur "n'est pas json sérialisable" en utilisant cela.

Voici comment je l'ai corrigé avec open("file-name.json", 'w')comme sortie:

output.write(str(response))

Bien que ce ne soit pas une bonne solution car le fichier json qu'il crée n'aura pas de guillemets doubles, cependant c'est génial si vous cherchez rapide et sale.

Akshat Bajaj
la source
0

Les données JSON peuvent être écrites dans un fichier comme suit

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

Écrivez dans un fichier:

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