2017-03-03 240 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))行。 –