2013-08-06 10 views
5

Załóżmy, że trzeba mieć plik bazy danych składają się z listy słowników:Dołącz lista słowników Python pliku bez ładowania to

file:

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

muszę mieć funkcję, która odbiera listę słowników pokazaną powyżej i dołączającą do pliku. Czy jest jakiś sposób, aby to osiągnąć, np. Używając json (lub jakiejkolwiek innej metody), bez ładowania pliku?

EDIT1: Uwaga: Potrzebne jest dodanie nowych słowników do już istniejącego pliku na dysku.

+0

Co rozumiesz przez "bez ładowania"? – user2357112

+0

Jednym ze sposobów jest załadowanie pliku do pamięci, dodanie do niego nowej listy i zrzucenie wyniku z powrotem na dysk. Czy można po prostu zapisać nową listę na dysku, dołączając ją do końca pliku bez wczytywania pliku do pamięci? – jazzblue

+0

Może to być przydatne: http://stackoverflow.com/questions/12460943/merging-pre-sorted-files-without-reading-everything-into-memory Załaduj nowy plik dict do nowego pliku, a następnie scal go może dwa pliki? –

Odpowiedz

18

Możesz użyć json do zrzutu dykt, po jednym w linii. Teraz każda linia jest pojedynczym dyktando json, które napisałeś. Utracisz zewnętrzną listę, ale możesz dodać rekordy za pomocą prostego dopisania do istniejącego pliku.

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) 

Lista może być montowane później

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

Plik wygląda

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

Wygląda na to, że faktycznie nie dodajesz słowników do istniejącego pliku na dysku, ale raczej tworzysz wszystkie słowniki w kodzie i zapisujesz je w pliku. Potrzebuję ich dołączyć do istniejącego pliku. Powinienem chyba zaznaczyć to w moim pierwotnym pytaniu. – jazzblue

+0

Nie, jego dołączanie do pliku, jak chcesz. Pętla for to tylko wersja demonstracyjna programu, który kilka razy dołącza rekordy do pliku. Uruchom demo dwa razy, a otrzymasz więcej rekordów na końcu. Będę edytować dla jasności. – tdelaney

+0

Dobre rozwiązanie, jeśli nie chcesz używać ładnego jsona (co sprawia, że ​​montaż jest trudniejszy, jeśli chcesz) – saeedgnu

4

Jeśli jest to konieczne, aby zachować plik jest poprawny json, można to zrobić w następujący sposób:

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

O zapisuje plik zarówno dla reading and writing. Następnie przechodzi do końca pliku (zero bajtów od końca), aby znaleźć położenie końca pliku (względem początku pliku) i zwraca ostatni bajt z powrotem, co w pliku json ma reprezentować znak ]. Ostatecznie dodaje nowy słownik do struktury, przesłaniając ostatni znak pliku i zachowując jego aktualność. Nie odczytuje pliku w pamięci. Przetestowano zarówno z kodowanymi plikami ANSI, jak i utf-8 w Pythonie 3.4.3 z małymi i dużymi (5 GB) plikami typu dummy.

wariacja, jeśli masz również os moduł przywożone:

import os, json 

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

To określa długość bajtów pliku, aby przejść do pozycji jeden bajt mniej (jak w poprzednim przykładzie).

1

Jeśli szukasz nie faktycznie załadować plik, dzieje się to z json nie jest tak naprawdę właściwym podejściem. Możesz użyć pliku odwzorowanego w pamięci ... i nigdy nie ładować pliku do pamięci - tablica memmap może otworzyć plik i zbudować tablicę "na dysku" bez ładowania czegokolwiek do pamięci.

Utwórz macierz pamięci odwzorowany z 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 

teraz czytać tablicę bez ładowania pliku:

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

zawartość pliku są ładowane do pamięci, gdy lista jest utworzone, ale to nie jest wymagane - możesz pracować z tablicą na dysku bez jej ładowania.

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

trwa pomijalny okres czasu (na przykład nanosekund) w celu utworzenia tablicy w pamięci, które może indeksować plik bez względu na wielkość (na przykład 100 GB) pliku.

0

Stosując takie samo podejście jak user3500511 ...

Załóżmy, że mamy dwie listy słowników (dicts, dicts2). Dicts są konwertowane na ciągi sformatowane w json. Dicts zostaje zapisany do nowego pliku - test.json. Test.json jest ponownie otwierany, a obiekty łańcuchowe są formatowane z odpowiednimi ogranicznikami. Przy ponownie sformatowanych obiektach można dodać dict2, a plik nadal zachowuje odpowiednią strukturę dla obiektu 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() 
Powiązane problemy