2013-08-06 46 views
5

Giả sử tôi cần phải có một tập tin cơ sở dữ liệu bao gồm một danh sách các từ điển:Nối danh sách các từ điển Python vào một tập tin mà không cần tải nó

file:

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

tôi cần phải có một chức năng tiếp nhận một danh sách các từ điển như được hiển thị ở trên và gắn nó vào tập tin. Có cách nào để đạt được điều đó, nói rằng bằng cách sử dụng json (hoặc bất kỳ phương pháp nào khác), mà không cần tải tập tin?

EDIT1: Lưu ý: Những gì tôi cần, là thêm các từ điển mới vào một tệp đã tồn tại trên đĩa.

+0

Ý bạn là gì khi "không tải"? – user2357112

+0

Vâng, một cách là tải tệp vào bộ nhớ, thêm danh sách mới vào đó và kết xuất kết quả lại vào đĩa. Có thể chỉ cần ghi danh sách mới vào đĩa, gắn nó vào cuối tập tin mà không cần tải tập tin vào bộ nhớ không? – jazzblue

+0

Điều này có thể được sử dụng: http://stackoverflow.com/questions/12460943/merging-pre-sorted-files-without-reading-everything-into-memory Tải dict mới vào một tệp mới, sau đó hợp nhất hai tập tin có lẽ? –

Trả lời

18

Bạn có thể sử dụng json để kết xuất các dicts, một dòng trên mỗi dòng. Bây giờ mỗi dòng là một dict json duy nhất mà bạn đã viết. Bạn mất danh sách bên ngoài, nhưng bạn có thể thêm các bản ghi với một phụ thêm đơn giản vào tệp hiện có.

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) 

Danh sách này có thể được lắp ráp sau

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

Các tập tin trông giống như

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

Ở đây có vẻ như bạn không thực sự thêm từ điển vào tệp hiện có trên đĩa, mà là tạo tất cả từ điển trong mã và viết chúng vào một tệp. Những gì tôi cần là để thêm chúng vào một tập tin hiện có. Tôi có lẽ nên lưu ý rằng trong câu hỏi ban đầu của tôi. – jazzblue

+0

Không, nó phụ thêm vào tệp như bạn muốn. Vòng lặp for chỉ là bản trình diễn của một chương trình nối thêm các bản ghi vào tệp nhiều lần. Chạy bản trình diễn hai lần và bạn sẽ thu được nhiều bản ghi hơn vào cuối. Tôi sẽ chỉnh sửa cho rõ ràng. – tdelaney

+0

Giải pháp tốt nếu bạn không muốn sử dụng json đẹp (điều này làm cho việc lắp ráp trở nên khó khăn hơn nếu bạn muốn) – saeedgnu

4

Nếu nó là cần thiết để giữ cho các tập tin được json hợp lệ, nó có thể được thực hiện như sau:

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

Điều này o bút tập tin cho cả hai reading and writing. Sau đó, nó đi đến cuối của tập tin (không byte từ cuối) để tìm ra vị trí của tập tin kết thúc (tương đối với đầu của tập tin) và đi cuối cùng một byte trở lại, mà trong một tập tin json dự kiến ​​sẽ đại diện cho nhân vật ]. Cuối cùng, nó thêm một từ điển mới vào cấu trúc, ghi đè ký tự cuối cùng của tập tin và giữ nó thành json hợp lệ. Nó không đọc tập tin vào bộ nhớ. Thử nghiệm với cả hai tệp được mã hóa ANSI và utf-8 trong Python 3.4.3 với các tệp giả nhỏ và lớn (5 GB).

Một biến thể, nếu bạn cũng có os mô-đun nhập khẩu:

import os, json 

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

Nó định nghĩa độ dài byte của tập tin để đi đến vị trí của một byte ít hơn (như trong ví dụ trước).

1

Nếu bạn đang tìm cách không thực sự tải tệp, hãy thực hiện điều này với json không thực sự là phương pháp phù hợp. Bạn có thể sử dụng một tệp ánh xạ bộ nhớ ... và không bao giờ thực sự tải tệp vào bộ nhớ - mảng memmap có thể mở tệp và tạo một mảng "trên đĩa" mà không tải bất kỳ thứ gì vào bộ nhớ.

Tạo một mảng bộ nhớ ánh xạ của 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 

Bây giờ đọc mảng, mà không cần tải file:

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

Nội dung của tập tin được nạp vào bộ nhớ khi danh sách là được tạo nhưng không cần thiết - bạn có thể làm việc với mảng trên đĩa mà không cần tải nó.

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

Phải mất một lượng đáng kể thời gian (ví dụ nano giây) để tạo ra một mảng bộ nhớ ánh xạ mà có thể chỉ mục một tập tin bất kể kích thước (ví dụ 100 GB) của tập tin.

0

Sử dụng phương pháp tương tự như user3500511 ...

Giả sử chúng ta có hai danh sách các từ điển (dicts, dicts2). Các dicts được chuyển đổi thành các chuỗi có định dạng json. Dicts được lưu vào một tệp mới - test.json. Test.json được mở lại và các đối tượng chuỗi được định dạng với các dấu phân cách thích hợp. Với các đối tượng được định dạng lại, dict2 có thể được nối thêm và tệp vẫn duy trì cấu trúc thích hợp cho một đối tượng 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() 
Các vấn đề liên quan