2017-03-03 281 views
1

我寫了一些Python代碼,用於保存JSON文件中的字典字典,並且我希望在文件末尾添加更多的字典(在主字典中),而不必加載和重寫所有字典。如何將新元素添加到JSON文件的末尾?

下面是一個例子,我最初的文件是這樣的:

{ "dict1": {"key1": 1.1, "key2": 1.2}, "dict2": {"key1": 2.1 "key2": 2.2}} 

我要添加"dict3": {"key1": 3.1, "key2": 3.2}它:

{ "dict1": {"key1": 1.1, "key2": 1.2}, "dict2": {"key1": 2.1 "key2": 2.2}, "dict3": {"key1": 3.1, "key2": 3.2}} 

我試圖"a"模式來打開文件,但它因關閉}而不工作。那麼有什麼方法可以覆蓋我的文件的最後一個字符或更聰明的方法來獲得相同的結果嗎?

+1

爲什麼你不想在內存中加載json並寫入更新的json? –

+0

以通用通用的方式來做到這一點可能會很棘手。但是,如果事先知道JSON文件的結構,只需在最後一個'}'字符前複製文件中的所有內容,添加所需的內容(使用逗號作爲您的示例中的內容),然後寫入最終的'}。 '。 – martineau

+0

@Budulianin因爲我將不得不重複這個過程許多時間,文件將變得有點巨大(我期望一些去),所以我想避免,如果可能 – Gabriel

回答

1

在位編輯數據文件是一個有點棘手和危險的。你必須修補原來的文件格式。通常閱讀整個文件的JSON更簡單,添加數據項,然後重新序列化並重寫文件。但是,出於表演和其他原因,熱補貼有時候是醫生訂購的。所以:

def append_to_json(filepath, data): 
    """ 
    Append data in JSON format to the end of a JSON file. 
    NOTE: Assumes file contains a JSON object (like a Python 
    dict) ending in '}'. 
    :param filepath: path to file 
    :param data: dict to append 
    """ 

    # construct JSON fragment as new file ending 
    new_ending = ", " + json.dumps(data)[1:-1] + "}\n" 

    # edit the file in situ - first open it in read/write mode 
    with open(filepath, 'r+') as f: 

     f.seek(0, 2)  # move to end of file 
     index = f.tell() # find index of last byte 

     # walking back from the end of file, find the index 
     # of the original JSON's closing '}' 
     while not f.read().startswith('}'): 
      index -= 1 
      if index == 0: 
       raise ValueError("can't find JSON object in {!r}".format(filepath)) 
      f.seek(index) 

     # starting at the original ending } position, write out 
     # the new ending 
     f.seek(index) 
     f.write(new_ending)  

# let 'er rip 
newval = {"dict3": {"key1": 3.1, "key2": 3.2}} 
append_to_json('data.json', newval) 

假設原始數據爲data.json,運行此之後,該文件將包含:

{ "dict1": {"key1": 1.1, "key2": 1.2}, 
    "dict2": {"key1": 2.1, "key2": 2.2}, 
    "dict3": {"key1": 3.1, "key2": 3.2}} 

(這裏JSON輸出已對齊,方便閱讀在該文件中,它可能會是一條極長的線)。

請注意,我保持這個簡單,所以它更容易遵循和理解。在實踐中,您會經常遇到第二種JSON文件:面向記錄的文件,它是一組對象([ {}, ... {}])。該風格以']'而不是'}'結尾。這個例程的更多開發版本也會查找這種情況。

+0

Thx你!我認爲這是我想要的esxactly! – Gabriel

-1

看一下這個,首先在打開文件後找到文件的最後一個字符,然後用re.sub()用'MyNewDic}'替換最後一個'}',不要忘記在'在開始和結束額外的「」當你代:

>>> s = '{ "dict1": {"key1": 1.1, "key2": 1.2}, "dict2": {"key1": 2.1 "key2": 2.2}}' 

>>> re.sub(r'}$',',"dict3": {"key1": 3.1, "key2": 3.2}}',s) 

它給了這一點放:

'{ "dict1": {"key1": 1.1, "key2": 1.2}, "dict2": {"key1": 2.1 "key2": 2.2},"dict3": {"key1": 3.1, "key2": 3.2}}' 
+0

你加載所有json在內存中不是一個解決方案。 –

0

我不認爲你應該建立一個巨大的JSON字符串。如果它真的是「比我的RAM大」,那麼你怎麼去後面使用呢?

我建議您使用合適的數據庫或一個簡單的格式,例如,每行一個條目是這樣的(這只是一個json.dumps(dictitem)每行):

["dict1", {"key1": 1.1, "key2": 1.2}] 
["dict2", {"key1": 2.1, "key2": 2.2}] 
["dict3", {"key1": 3.1, "key2": 3.2}] 

然後,你可以簡單地添加一個條目/行到文件,並解析文件也很容易。和內存效率。

with open('data.txt') as f: 
    for line in f: 
     key, value = json.loads(line) 
     ... 
+0

如果你可以擺動它,好主意構造文件以方便追加。甚至還有一個標準,[RFC 7464](https://tools.ietf.org/html/rfc7464)。儘管如此,我沒有看到你所建議的特定每行數組格式的優點。它是JSON,但是鍵/字典名稱和值之間的關係被省略了。爲什麼不是每行一個對象'{「dict3」:{「key1」:3.1,「key2」:3.2}}'?這保留了追加能力和對象結構。 –

+0

@JonathanEunice我認爲你的工作更多,無論是寫作還是閱讀。或者你可以做一些像'key,value = json.loads(line)'一樣好的東西嗎?或者像'dict(map(json.loads,f))'那樣很好地創建整個字典(如果內存允許的話)''?我只是想把字典項目寫入文件,字典項目是成對的,而不是字典本身。 –

+0

關於鍵值對的固體點。但是全字典也不難管理。 'd = json.loads(line)'per line,或'd = {};對於整個字典中的f:d.update(json.loads(line))行。 –

相關問題