2016-04-24 63 views
7

我有一個很大的for loop,我在其中創建了json對象,我希望能夠將每次迭代中的對象寫入一個文件。我希望稍後能夠以類似的方式使用該文件(一次讀取一個對象)。 我的json對象包含換行符,我不能將每個對象轉儲爲文件中的一行。 我該如何做到這一點?Python,將json/dictionary對象迭代地寫入一個文件(每次一個)

爲了使它更具體,考慮以下因素:

for _id in collection: 
    dict_obj = build_dict(_id) # build a dictionary object 
    with open('file.json', 'a') as f: 
     stream_dump(dict_obj, f) 

stream_dump是我想要的功能。

請注意,我不想創建一個大列表並使用類似json.dump(obj, file)這樣的轉儲整個列表。我希望能夠在每次迭代中將對象追加到文件中。

謝謝。

+0

如果我不明白你的問題是錯誤的,似乎有可能編寫一個分隔符行,在你寫對象之後的每一次迭代中,你的數據不會有像「-----」那樣的分隔符,當你看到分隔符時創建一個新對象。 – alpert

+0

啊,我明白了。這絕對有效。我認爲可能有其他流處理解決方案。 – CentAu

回答

3

您需要的JSONEncoder一個子類,然後代理build_dict功能

from __future__ import (absolute_import, division, print_function,) 
#      unicode_literals) 

import collections 
import json 


mycollection = [1, 2, 3, 4] 


def build_dict(_id): 
    d = dict() 
    d['my_' + str(_id)] = _id 
    return d 


class SeqProxy(collections.Sequence): 
    def __init__(self, func, coll, *args, **kwargs): 
     super(SeqProxy, *args, **kwargs) 

     self.func = func 
     self.coll = coll 

    def __len__(self): 
     return len(self.coll) 

    def __getitem__(self, key): 
     return self.func(self.coll[key]) 


class JsonEncoderProxy(json.JSONEncoder): 
    def default(self, o): 
     try: 
      iterable = iter(o) 
     except TypeError: 
      pass 
     else: 
      return list(iterable) 
     # Let the base class default method raise the TypeError 
     return json.JSONEncoder.default(self, o) 


jsonencoder = JsonEncoderProxy() 
collproxy = SeqProxy(build_dict, mycollection) 


for chunk in jsonencoder.iterencode(collproxy): 
    print(chunk) 

輸出繼電器的工作:

[ 
{ 
"my_1" 
: 
1 
} 
, 
{ 
"my_2" 
: 
2 
} 
, 
{ 
"my_3" 
: 
3 
} 
, 
{ 
"my_4" 
: 
4 
} 
] 

要由塊讀回塊,你需要使用JSONDecoder和傳遞可致電object_hook。這個鉤子會隨着每個新解碼的對象(在你的列表中的每個dict)被調用,當你調用JSONDecoder.decode(json_string)

+0

完美,謝謝。只是一個問題,'SeqProxy'做了什麼? – CentAu

+1

您的集合將不會爲每個項目返回一個「字典」(您在每個項目上調用'build_dict'),並且'SeqProxy'封裝您的集合,並在'JSONEncoder'請求下一個項目時返回'build_dict'的結果列表來序列化它。 – mementum

+0

如果我錯了,請糾正我:這解決了兩個問題:(a)代理需要調用集合的特定子集上的自定義'build_dict'函數; (b)通過'iterencode'函數已經由JSON模塊提供了按塊進行串行化的任務。 - 我專注於(b),直到意識到完全關於(a),才明白代碼。 – lenz

2

既然你生成自己的文件,你可以簡單地寫出每行一個JSON對象:

for _id in collection: 
    dict_obj = build_dict(_id) # build a dictionary object 
    with open('file.json', 'a') as f: 
     f.write(json.dumps(dict_obj)) 
     f.write('\n') 

然後通過迭代線讀他們:

with open('file.json', 'r') as f: 
    for line in f: 
     dict_obj = json.loads(line) 

這是不是一個偉大的通用的解決方案,但它是一個簡單的,如果你是兩個發電機和消費國。

-1

簡單的解決方案:

從您的JSON文檔的所有空格字符:

import string 

def remove_whitespaces(txt): 
    """ We shall remove all whitespaces""" 
    for chr in string.whitespace: 
     txt = txt.replace(chr) 

很明顯,你也json.dumps(json.loads(json_txt))(順便說一句,這也驗證該文本是一個有效的JSON)。

現在,您可以將文檔寫入每個文件一行。

解決方法二:

創建[AnyStr]木衛一流,在IO寫一個有效的文件,(你的文檔作爲一個對象或列表的一部分),然後寫在一個文件中的IO(或上傳到雲)。

+2

如果空白是內容的組成部分,會發生什麼? – mementum

+0

好的觀察!無論如何,json.dumps(json.loads(json_txt))在這種情況下是完美的。 –

+0

你爲什麼要刪除所有的空白?我不明白這是如何連接到OP。如果你想在一行上完成JSON轉儲,請執行'json.dump(... indent = None)'(實際上,它已經是默認了)。無論如何,文本節點內的換行符都會被轉義。 – lenz

相關問題