Python:尝试对文件中的多个JSON对象进行反序列化,每个对象跨越多个但间隔一致的行数

 好好地经历这每一天 发布于 2023-02-12 17:20

好吧,经过近一周的研究,我将给予一个机会.我有一个文本文件,如下所示(显示3个单独的json对象作为示例,但文件有50K这些):

{
"zipcode":"00544",
"current":{"canwc":null,"cig":7000,"class":"observation"},
"triggers":[178,30,176,103,179,112,21,20,48,7,50,40,57]
}
{
"zipcode":"00601",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[12,23,34,28,100]
}
{
"zipcode":"00602",
"current":{"canwc":null,"cig":null,"class":"observation"},
"triggers":[13,85,43,101,38,31]
}

我知道如何使用Python json库处理JSON对象,但是我对如何通过读取文件创建5万个不同的json对象提出了挑战.(也许我甚至没有正确地思考这个问题,但最终我需要反序列化并加载到数据库中)我已经尝试过itertools认为我需要一个生成器,所以我能够使用:

with open(file) as f:
    for line in itertools.islice(f, 0, 7): #since every 7 lines is a json object
        jfile = json.load(line)

但是上面显然不会起作用,因为它不是将7行作为单个json对象读取,而且我也不确定如何迭代整个文件并加载单个json对象.

以下将给我一个我可以切片的列表:

list(open(file))[:7]

任何帮助将非常感激.


非常接近我需要的东西,我认为只有一步之遥,但仍然在迭代中苦苦挣扎.这最终会让我对所有数据帧进行迭代打印输出,但是如何制作它以便我可以捕获一个巨大的数据帧,其中所有的部分基本上连接在一起?然后我可以将最终的数据帧导出到csv等.(还有更好的方法将此结果上传到数据库而不是先创建一个巨大的数据帧吗?)

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

def flatten(jfile):
    for k, v in jfile.items():
        if isinstance(v, list):
            jfile[k] = ','.join(v)
        elif isinstance(v, dict):
            for kk, vv in v.items():
                jfile['%s' % (kk)] = vv
            del jfile[k]
            return jfile

with open('deadzips.json') as f:
    for chunk in lines_per_n(f, 7):
        try:
            jfile = json.loads(chunk)
            pd.DataFrame(flatten(jfile).items())
        except ValueError, e:
            pass
        else:
            pass

Martijn Piet.. 24

加载6个额外的行,并将字符串传递给json.loads():

with open(file) as f:
    for line in f:
        # slice the next 6 lines from the iterable, as a list.
        lines = [line] + list(itertools.islice(f, 6))
        jfile = json.loads(''.join(lines))

        # do something with jfile

json.load()将不仅仅是文件中的下一个对象,而且islice(f, 0, 7)只读取前7行,而不是读取7行块中的文件.

您可以在生成器中以大小为N的块读取文件:

from itertools import islice, chain

def lines_per_n(f, n):
    for line in f:
        yield ''.join(chain([line], itertools.islice(f, n - 1)))

然后用它来填充你的输入文件:

with open(file) as f:
    for chunk in lines_per_n(f, 7):
        jfile = json.loads(chunk)

        # do something with jfile

或者,如果您的块变为长度可变,请阅读,直到您有解析的内容为止:

with open(file) as f:
    for line in f:
        while True:
            try:
                jfile = json.loads(line)
                break
            except ValueError:
                # Not yet a complete JSON value
                line += next(f)

        # do something with jfile

至于你的第二个解决方案,`JSONDecoder.raw_decode`基本上是为你做的. (4认同)


Jeff Younker.. 9

如其他地方所述,一般的解决方案是将文件分片读取,将每个片段附加到最后,并尝试解析该新块.如果它不解析,继续,直到你得到的东西.一旦你有解析的东西,返回它,然后重新启动过程.冲洗 - 泡沫重复,直到数据用完为止.

这是一个简洁的生成器,它将执行此操作:

def load_json_multiple(segments):
    chunk = ""
    for segment in segments:
        chunk += segment
        try:
            yield json.loads(chunk)
            chunk = ""
        except ValueError:
            pass

像这样使用它:

with open('foo.json') as f:
   for parsed_json in load_json_multiple(f):
      print parsed_json

我希望这有帮助.

2 个回答
  • 如其他地方所述,一般的解决方案是将文件分片读取,将每个片段附加到最后,并尝试解析该新块.如果它不解析,继续,直到你得到的东西.一旦你有解析的东西,返回它,然后重新启动过程.冲洗 - 泡沫重复,直到数据用完为止.

    这是一个简洁的生成器,它将执行此操作:

    def load_json_multiple(segments):
        chunk = ""
        for segment in segments:
            chunk += segment
            try:
                yield json.loads(chunk)
                chunk = ""
            except ValueError:
                pass
    

    像这样使用它:

    with open('foo.json') as f:
       for parsed_json in load_json_multiple(f):
          print parsed_json
    

    我希望这有帮助.

    2023-02-12 17:23 回答
  • 加载6个额外的行,并将字符串传递给json.loads():

    with open(file) as f:
        for line in f:
            # slice the next 6 lines from the iterable, as a list.
            lines = [line] + list(itertools.islice(f, 6))
            jfile = json.loads(''.join(lines))
    
            # do something with jfile
    

    json.load()将不仅仅是文件中的下一个对象,而且islice(f, 0, 7)只读取前7行,而不是读取7行块中的文件.

    您可以在生成器中以大小为N的块读取文件:

    from itertools import islice, chain
    
    def lines_per_n(f, n):
        for line in f:
            yield ''.join(chain([line], itertools.islice(f, n - 1)))
    

    然后用它来填充你的输入文件:

    with open(file) as f:
        for chunk in lines_per_n(f, 7):
            jfile = json.loads(chunk)
    
            # do something with jfile
    

    或者,如果您的块变为长度可变,请阅读,直到您有解析的内容为止:

    with open(file) as f:
        for line in f:
            while True:
                try:
                    jfile = json.loads(line)
                    break
                except ValueError:
                    # Not yet a complete JSON value
                    line += next(f)
    
            # do something with jfile
    

    2023-02-12 17:24 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有