【问题标题】:Python, write json / dictionary objects to a file iteratively (one at a time)Python,将 json / 字典对象迭代地写入文件(一次一个)
【发布时间】:2016-08-18 01:11:29
【问题描述】:

我有一个大的for loop,我在其中创建 json 对象,我希望能够在每次迭代中将对象流式写入文件。我希望以后能够以类似的方式使用该文件(一次读取一个对象)。 我的 json 对象包含换行符,我不能将每个对象作为文件中的一行转储。 我怎样才能做到这一点?

为了更具体,请考虑以下几点:

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) 之类的东西转储整个列表。我希望能够在每次迭代中将对象附加到文件中。

谢谢。

【问题讨论】:

  • 如果我不明白你的问题是错误的,在你写对象和读取创建一个新对象后,在每次迭代中,你的数据似乎都没有像“-----”这样的分隔线当你看到那个分隔符时。
  • 啊,我明白了。这绝对有效。我认为可能还有其他流处理解决方案。

标签: python json dictionary


【解决方案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 中写入有效文档(您的文档是对象或列表的一部分),然后将 io 写入文件(或将其上传到云端)。

【讨论】:

  • 如果空白是内容的一个组成部分会怎样?
  • 好观察!无论如何 json.dumps(json.loads(json_txt)) 在这种情况下是完美的。
  • 为什么要删除所有空格?我不明白这是如何连接到 OP 的。如果您想在一行中包含完整的 JSON 转储,请执行 json.dump(... indent=None)(实际上,它已经是默认设置了)。文本节点内的换行符无论如何都会被转义。
【解决方案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)

这不是一个很好的通用解决方案,但如果您既是生成者又是消费者,它是一个简单的解决方案。

【讨论】:

    【解决方案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 传递。当您调用 JSONDecoder.decode(json_string) 时,将使用每个新的解码对象(列表中的每个 dict)调用此钩子

    【讨论】:

    • 完美,谢谢。只是一个问题,SeqProxy 是做什么的?
    • 您的集合不会为每个项目返回一个“dict”(您在每个项目上调用build_dict)并且SeqProxy 包装您的集合并在@987654333 时返回build_dict 的结果@ 请求列表中的下一项对其进行序列化。
    • 如果我错了,请纠正我:这解决了两个问题:(a) 需要代理来调用集合的特定子集上的自定义 build_dict 函数; (b) JSON 模块已经通过iterencode 函数提供了逐块序列化的任务。 – 我专注于(b)并且直到意识到它都是关于(a)时才理解代码。
    猜你喜欢
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-07
    相关资源
    最近更新 更多