2013-08-06 9 views
5

Supponiamo che ho bisogno di avere un file di database costituito da un elenco di dizionari:lista di accodamento di Python dizionari in un file senza caricarla

di file:

[ 
    {"name":"Joe","data":[1,2,3,4,5]}, 
    { ...       }, 
      ... 
] 

ho bisogno di avere una funzione che riceve un elenco di dizionari come mostrato sopra e lo aggiunge al file. C'è un modo per ottenerlo, ad esempio usando json (o qualsiasi altro metodo), senza caricare il file?

EDIT1: Nota: Ciò di cui ho bisogno è di aggiungere nuovi dizionari a un file già esistente sul disco.

+0

Cosa intendete per "senza caricarlo"? – user2357112

+0

Bene, un modo è quello di caricare il file nella memoria, aggiungere la nuova lista ad esso e scaricare il risultato sul disco. È possibile scrivere semplicemente il nuovo elenco sul disco, aggiungendolo alla fine del file senza caricare il file nella memoria? – jazzblue

+0

Questo potrebbe essere utile: http://stackoverflow.com/questions/12460943/merging-pre-sorted-files-without-reading-everything-into-memory Caricare la nuova dict in un nuovo file, e quindi unire i due file forse? –

risposta

18

È possibile utilizzare json per scaricare i dit, uno per riga. Ora ogni riga è una singola frase che hai scritto. Si perde l'elenco esterno, ma è possibile aggiungere record con una semplice append al file esistente.

import json 
import os 

def append_record(record): 
    with open('my_file', 'a') as f: 
     json.dump(record, f) 
     f.write(os.linesep) 

# demonstrate a program writing multiple records 
for i in range(10): 
    my_dict = {'number':i} 
    append_record(my_dict) 

La lista può essere montato successivamente

with open('my_file') as f: 
    my_list = [json.loads(line) for line in f] 

Il file si presenta come

{"number": 0} 
{"number": 1} 
{"number": 2} 
{"number": 3} 
{"number": 4} 
{"number": 5} 
{"number": 6} 
{"number": 7} 
{"number": 8} 
{"number": 9} 
+0

Qui sembra che non si stiano effettivamente accodando dizionari al file esistente sul disco, ma piuttosto creando tutti i dizionari nel codice e scrivendoli in un file. Quello di cui ho bisogno è di aggiungerli a un file esistente. Dovrei probabilmente notarlo nella mia domanda iniziale. – jazzblue

+0

No, si accoda al file come si desidera. Il ciclo for è solo una demo di un programma che aggiunge i record al file più volte. Esegui la demo due volte e otterrai più record alla fine. Modificherò per chiarezza. – tdelaney

+0

Buona soluzione se non si vuole usare abbastanza json (il che rende l'assemblaggio della parte più difficile se lo si desidera) – saeedgnu

4

Se è necessario per mantenere il file essendo JSON valido, può essere fatto come segue:

import json 

with open (filepath, mode="r+") as file: 
    file.seek(0,2) 
    position = file.tell() -1 
    file.seek(position) 
    file.write(",{}]".format(json.dumps(dictionary))) 

Questo o penne il file sia per reading and writing. Quindi, va alla fine del file (zero byte dalla fine) per trovare la posizione finale del file (relativamente all'inizio del file) e torna all'ultimo byte, che in un file json è previsto per rappresentare il carattere ]. Alla fine, aggiunge un nuovo dizionario alla struttura, sovrascrivendo l'ultimo carattere del file e conservandolo come json valido. Non legge il file nella memoria. Testato con entrambi i file codificati ANSI e utf-8 in Python 3.4.3 con file dummy piccoli e grandi (5 GB).

Una variante, se avete anche os modulo importato:

import os, json 

with open (filepath, mode="r+") as file: 
    file.seek(os.stat(filepath).st_size -1) 
    file.write(",{}]".format(json.dumps(dictionary))) 

definisce la lunghezza in byte del file per andare alla posizione di un byte di meno (come nell'esempio precedente).

1

Se non si desidera effettivamente il caricare il file, andare su questo con json non è proprio l'approccio giusto. È possibile utilizzare un file mappato in memoria ... e non caricare mai effettivamente il file in memoria: un array memmap può aprire il file e creare un array "su disco" senza caricare nulla nella memoria.

Creare un array di memoria mappata di dicts:

>>> import numpy as np 
>>> a = np.memmap('mydict.dat', dtype=object, mode='w+', shape=(4,)) 
>>> a[0] = {'name':"Joe", 'data':[1,2,3,4]} 
>>> a[1] = {'name':"Guido", 'data':[1,3,3,5]} 
>>> a[2] = {'name':"Fernando", 'data':[4,2,6,9]} 
>>> a[3] = {'name':"Jill", 'data':[9,1,9,0]} 
>>> a.flush() 
>>> del a 

Ora leggere la matrice, senza caricare il file:

>>> a = np.memmap('mydict.dat', dtype=object, mode='r') 

Il contenuto del file vengono caricati in memoria quando la lista è creato, ma non è necessario - puoi lavorare con l'array su disco senza caricarlo.

>>> a.tolist() 
[{'data': [1, 2, 3, 4], 'name': 'Joe'}, {'data': [1, 3, 3, 5], 'name': 'Guido'}, {'data': [4, 2, 6, 9], 'name': 'Fernando'}, {'data': [9, 1, 9, 0], 'name': 'Jill'}] 

Si prende una quantità trascurabile di tempo (ad esempio nanosecondi) per creare una matrice di memoria mappata che può indicizzare un file indipendentemente dalle dimensioni (ad esempio 100 GB) del file.

0

Utilizzando lo stesso approccio user3500511 ...

Supponiamo di avere due elenchi di dizionari (dicts, dicts2). I dicts vengono convertiti in stringhe in formato json. Dicts viene salvato in un nuovo file - test.json. Test.json viene riaperto e gli oggetti stringa vengono formattati con i delimitatori appropriati. Con gli oggetti riformattati, è possibile aggiungere dict2 e il file mantiene ancora la struttura corretta per un oggetto JSON.

import json 

dicts = [{ "name": "Stephen", "Number": 1 } 
     ,{ "name": "Glinda", "Number": 2 } 
     ,{ "name": "Elphaba", "Number": 3 } 
     ,{ "name": "Nessa", "Number": 4 }] 

dicts2= [{ "name": "Dorothy", "Number": 5 } 
     ,{ "name": "Fiyero", "Number": 6 }] 


f = open("test.json","w") 
f.write(json.dumps(dicts)) 
f.close() 

f2 = open("test.json","r+") 
f2.seek(-1,2) 
f2.write(json.dumps(dicts2).replace('[',',',1)) 
f2.close() 

f3 = open('test.json','r') 
f3.read() 
Problemi correlati