web-dev-qa-db-fra.com

Ajout de données à un fichier JSON en Python

J'essaye de créer une fonction qui ajouterait des entrées à un fichier json. Finalement, je veux un fichier qui ressemble à 

[{"name" = "name1", "url" = "url1"}, {"name" = "name2", "url" = "url2"}]

etc. Voici ce que j'ai:

def add(args):
    with open(DATA_FILENAME, mode='r', encoding='utf-8') as feedsjson:
        feeds = json.load(feedsjson)
    with open(DATA_FILENAME, mode='w', encoding='utf-8') as feedsjson:
        entry = {}
        entry['name'] = args.name
        entry['url'] = args.url
        json.dump(entry, feedsjson)

Cela crée une entrée telle que {"name"="some name", "url"="some url"}. Mais si j'utilise à nouveau cette fonction add, avec un nom et une URL différents, la première est écrasée. Que dois-je faire pour obtenir une deuxième (troisième ...) entrée ajoutée à la première?

EDIT: Les premières réponses et commentaires à cette question ont mis en évidence le fait évident que je n'utilise pas feeds dans le bloc d'écriture. Je ne vois pas comment faire cela, cependant. Par exemple, ce qui suit ne semble apparemment pas suffire:

with open(DATA_FILENAME, mode='a+', encoding='utf-8') as feedsjson:
    feeds = json.load(feedsjson)
    entry = {}
    entry['name'] = args.name
    entry['url'] = args.url
    json.dump(entry, feeds)
27
Schiphol

Vous voudrez probablement utiliser une liste JSON list au lieu d’un dictionnaire en tant qu’élément de niveau supérieur.

Donc, initialisez le fichier avec une liste vide:

with open(DATA_FILENAME, mode='w', encoding='utf-8') as f:
    json.dump([], f)

Ensuite, vous pouvez ajouter nouvelles entrées à cette liste:

with open(DATA_FILENAME, mode='w', encoding='utf-8') as feedsjson:
    entry = {'name': args.name, 'url': args.url}
    feeds.append(entry)
    json.dump(feeds, feedsjson)

Notez que l’exécution sera lente car vous devrez réécrire le contenu complet du fichier chaque fois que vous appelez add. Si vous l'appelez en boucle, pensez à ajouter tous les flux à une liste à l'avance, puis à l'écrire en une fois.

29
nneonneo

json n'est peut-être pas le meilleur choix pour les formats sur disque; Le problème qu’il a avec l’ajout de données est un bon exemple de la raison pour laquelle cela pourrait être. Plus précisément, les objets json ont une syntaxe qui signifie que l’ensemble de l’objet doit être lu et analysé pour en comprendre une partie quelconque.

Heureusement, il y a beaucoup d'autres options. Le format CSV est particulièrement simple. qui est bien supporté par la bibliothèque standard de python. Le plus gros inconvénient est que cela ne fonctionne que pour le texte; cela nécessite une action supplémentaire de la part du programmeur pour convertir les valeurs en nombres ou autres formats, si nécessaire.

Une autre option qui ne présente pas cette limitation consiste à utiliser une base de données sqlite, qui prend également en charge python. Ce serait probablement un plus grand changement par rapport au code que vous avez déjà, mais cela prend plus naturellement en charge le modèle de modification d'un peu que vous essayez apparemment de construire.

Ajouter une entrée au contenu du fichier s'il existe, sinon ajouter l'entrée à une liste vide et écrire dans le fichier:

a = []
if not os.path.isfile(fname):
    a.append(entry)
    with open(fname, mode='w') as f:
        f.write(json.dumps(a, indent=2))
else:
    with open(fname) as feedsjson:
        feeds = json.load(feedsjson)

    feeds.append(entry)
    with open(fname, mode='w') as f:
        f.write(json.dumps(feeds, indent=2))
9
NargesooTv

Utiliser a au lieu de w devrait vous permettre de mettre à jour le fichier au lieu de créer un nouveau fichier/de tout écraser dans le fichier existant.

Voir cette réponse pour une différence dans les modes.

5
Susan Wright

Une solution possible est de faire la concaténation manuellement, voici quelques informations utiles Code:

import json
def append_to_json(_dict,path): 
    with open(path, 'ab+') as f:
    f.seek(0,2)                                #Go to the end of file    
    if f.tell() == 0 :                         #Check if file is empty
        f.write(json.dumps([_dict]).encode())  #If empty, write an array
    else :
        f.seek(-1,2)           
        f.truncate()                           #Remove the last character, open the array
        f.write(' , '.encode())                #Write the separator
        f.write(json.dumps(_dict).encode())    #Dump the dictionary
        f.write(']'.encode())                  #Close the array

Soyez prudent lorsque vous modifiez le fichier en dehors du script et n’ajoutez aucun espacement à la fin.

3
SEDaradji

Vous n'écrivez jamais rien à voir avec les données que vous avez lues. Voulez-vous ajouter la structure de données dans les flux au nouveau que vous créez?

Ou peut-être souhaitez-vous ouvrir le fichier en mode annexe open(filename, 'a'), puis ajouter votre chaîne en écrivant la chaîne générée par json.dumps au lieu d'utiliser json.dump - mais nneonneo indique que cela ne serait pas valide.

2
Thomas

J'ai du code qui est similaire, mais ne réécrit pas tout le contenu à chaque fois. Cela est censé être exécuté périodiquement et ajouter une entrée JSON à la fin d'un tableau.

Si le fichier n'existe pas encore, il le crée et vide le JSON dans un tableau. Si le fichier a déjà été créé, il passe à la fin, remplace le ] par un , et laisse tomber le nouvel objet JSON, puis le referme avec un autre ]

# Append JSON object to output file JSON array
fname = "somefile.txt"
if os.path.isfile(fname):
    # File exists
    with open(fname, 'a+') as outfile:
        outfile.seek(-1, os.SEEK_END)
        outfile.truncate()
        outfile.write(',')
        json.dump(data_dict, outfile)
        outfile.write(']')
else: 
    # Create file
    with open(fname, 'w') as outfile:
        array = []
        array.append(data_dict)
        json.dump(array, outfile)
0
Matt