【问题标题】:Append list of Python dictionaries to a file without loading it将 Python 字典列表附加到文件而不加载它
【发布时间】:2013-08-07 21:15:33
【问题描述】:

假设我需要一个包含字典列表的数据库文件:

文件:

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

我需要一个函数来接收如上所示的字典列表并将其附加到文件中。有什么方法可以实现,比如使用 json(或任何其他方法),而不加载文件?

编辑1: 注意:我需要的是将新词典附加到光盘上已有的文件中。

【问题讨论】:

  • “不加载”是什么意思?
  • 嗯,一种方法是将文件加载到内存中,将新列表附加到其中并将结果转储回磁盘。是否可以只将新列表写入光盘,将其附加到文件末尾而不将文件加载到内存中?
  • 这可能有用:stackoverflow.com/questions/12460943/… 将新字典加载到新文件中,然后合并两个文件?

标签: python json pickle


【解决方案1】:

您可以使用 json 转储字典,每行一个。现在每一行都是您编写的单个 json 字典。您松开外部列表,但您可以通过简单的附加到现有文件添加记录。

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)

列表可以稍后组装

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

文件看起来像

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

【讨论】:

  • 这里看起来您实际上并没有将字典附加到光盘上的现有文件,而是在代码中创建所有字典并将它们写入文件。我需要将它们附加到现有文件中。我可能应该在我原来的问题中注意到这一点。
  • 不,它可以根据需要附加到文件中。 for 循环只是一个程序的演示,它多次将记录附加到文件中。运行演示两次,您最终会获得更多记录。为了清楚起见,我将进行编辑。
  • 如果您不想使用漂亮的 json,这是一个很好的解决方案(如果您愿意,这会使组装零件变得更加困难)
  • @ilius - 是的,记录文件不应该是漂亮的!这真的是一个你想用什么作为记录分隔符的问题。如果您不打印,那么 json 将不会添加任何新行,这是一个很好的分隔符(这就是我在这里所做的)。如果你想要漂亮的打印,你可以选择类似 '\n---\n' 但你必须扫描它并自己做记录屏蔽。
【解决方案2】:

如果需要保持文件为合法的json,可以如下:

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

这将打开两个reading and writing 的文件。然后,它转到文件末尾(从末尾开始的零字节)以找出文件末尾的位置(相对于文件开头)并返回最后一个字节,在 json 文件中预计代表字符]。最后,它将一个新字典附加到结构中,覆盖文件的最后一个字符并保持它是有效的 json。它不会将文件读入内存。在 Python 3.4.3 中使用 ANSI 和 utf-8 编码文件进行了测试,其中包含小型和大型 (5 GB) 虚拟文件。

一个变体,如果您还导入了 os 模块:

import os, json

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

它定义文件的字节长度到少一个字节的位置(如前面的例子)。

【讨论】:

    【解决方案3】:

    如果您不想真正加载该文件,那么使用json 进行此操作并不是真正正确的方法。您可以使用内存映射文件……并且永远不会将文件实际加载到内存中——memmap 数组可以打开文件并在“磁盘上”构建一个数组,而无需将任何内容加载到内存中。

    创建一个内存映射的字典数组:

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

    现在读取数组,不加载文件:

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

    文件的内容会在创建列表时加载到内存中,但这不是必需的——您可以在不加载磁盘的情况下使用磁盘上的数组。

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

    创建一个可以索引文件的内存映射数组所需的时间(例如纳秒)可以忽略不计,而不管文件的大小(例如 100 GB)。

    【讨论】:

      【解决方案4】:

      使用与user3500511相同的方法...

      假设我们有两个字典列表(dicts、dicts2)。 dicts 被转换为 json 格式的字符串。字典被保存到一个新文件 - test.json。 Test.json 被重新打开,字符串对象使用正确的分隔符格式化。使用重新格式化的对象,可以附加 dict2 并且文件仍然保持 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()
      

      【讨论】:

        猜你喜欢
        • 2020-10-14
        • 1970-01-01
        • 2023-02-02
        • 1970-01-01
        • 2019-11-07
        • 1970-01-01
        • 1970-01-01
        • 2019-03-25
        • 2020-12-06
        相关资源
        最近更新 更多