【问题标题】:How to read line-delimited JSON from large file (line by line)如何从大文件中读取行分隔的 JSON(逐行)
【发布时间】:2014-02-27 07:47:47
【问题描述】:

我正在尝试加载一个用换行符分隔的 JSON 字符串填充的大文件(2GB 大小)。例如:

{
    "key11": value11,
    "key12": value12,
}
{
    "key21": value21,
    "key22": value22,
}
…

我现在导入的方式是:

content = open(file_path, "r").read() 
j_content = json.loads("[" + content.replace("}\n{", "},\n{") + "]")

这似乎是一种 hack(在每个 JSON 字符串之间添加逗号以及一个开始和结束方括号以使其成为正确的列表)。

有没有更好的方法来指定 JSON 分隔符(换行符 \n 而不是逗号 ,)?

另外,Python 似乎无法为从 2GB 数据构建的对象正确分配内存,有没有办法在我逐行读取文件时构造每个 JSON 对象?谢谢!

【问题讨论】:

  • 此时只需读取每一行,构造一个json对象
  • @njzk2:我认为问题在于 JSON 对象内部有换行符,而不仅仅是它们之间,对吧?
  • JSON 对象之间有换行符,在它们内部,是的。替换函数之所以有效,是因为换行符分隔右大括号和左大括号(“}”和“{”)的唯一位置是对象之间。我仍然不想依赖它来加载 JSON。
  • @Arkady,Cat:看到我的答案的结尾,有人写了一个解析器来说明这类事情,我认为这应该可以解决你的问题。

标签: python json parsing large-files


【解决方案1】:

此时只要读取每一行,构造一个json对象:

with open(file_path) as f:
    for line in f:
        j_content = json.loads(line)

这样,您可以加载正确的完整 json 对象(前提是某个 json 值中的某处或您的 json 对象中间没有 \n),并且您可以避免内存问题,因为每个对象都是在需要时创建的。

也有这个答案:

https://stackoverflow.com/a/7795029/671543

【讨论】:

  • 感谢分享链接,@njzk2 你写的代码不太好用:json.loads 如果你在部分 JSON 字符串上调用它会引发异常...
  • 是的,因此我的评论provided there is no \n (...) in the middle of your json object。否则,我添加的链接将指向适用于您的场景的解析器的答案。
  • json.loads 失败,因为 JSON 对象之间没有逗号,无论是否存在换行符...
  • 没有。 json.loads 失败,因为该行不包含完整的 jsonobject。 for line in f 在文件的行上循环。如果一行不包含完整的 jsonobject(例如拆分为几行),则失败。
  • 另外,也许更简洁地说,[json.loads(line) for line in f] 可以在单行中编写代码,并且将来可以嵌套。
【解决方案2】:

这适用于您提供的特定文件格式。如果您的格式发生变化,那么您将需要更改解析行的方式。

{
    "key11": 11,
    "key12": 12
}
{
    "key21": 21,
    "key22": 22
}

只需逐行阅读,然后构建 JSON 块:

with open(args.infile, 'r') as infile:

    # Variable for building our JSON block
    json_block = []

    for line in infile:

        # Add the line to our JSON block
        json_block.append(line)

        # Check whether we closed our JSON block
        if line.startswith('}'):

            # Do something with the JSON dictionary
            json_dict = json.loads(''.join(json_block))
            print(json_dict)

            # Start a new block
            json_block = []

如果您有兴趣解析一个非常大的 JSON 文件而不将所有内容保存到内存中,您应该考虑使用 json.load API 中的 object_hook 或 object_pairs_hook 回调方法。

【讨论】:

    【解决方案3】:
    contents = open(file_path, "r").read() 
    data = [json.loads(str(item)) for item in contents.strip().split('\n')]
    

    【讨论】:

      【解决方案4】:

      只需逐行读取并通过流解析 e 而你的黑客技巧(在每个 JSON 字符串之间添加逗号以及开始和结束方括号以使其成为正确的列表)如果文件超过 1GB,则对内存不友好,因为整个内容将落在 RAM 上。

      【讨论】:

        【解决方案5】:

        逐行阅读方法很好,正如上面一些答案中提到的那样。

        但是,对于多个 JSON 树结构,我建议将其分解为 2 个函数以进行更稳健的错误处理。

        例如,

        def load_cases(file_name):
            with open(file_name) as file:
                cases = (parse_case_line(json.loads(line)) for line in file)
                cases = filter(None, cases)
                return list(cases)
        

        parse_case_line 可以封装上述示例中所需的密钥解析逻辑,例如正则表达式匹配或特定于应用程序的要求。这也意味着您可以选择要解析出的json键值。

        这种方法的另一个优点是filter 在您的 json 对象中间处理多个 \n,并解析整个文件 :-)。

        【讨论】:

          【解决方案6】:

          必须从 AWS S3 读取一些数据并解析一个换行符分隔的 jsonl 文件。我的解决方案是使用splitlines

          代码:

          for line in json_input.splitlines():
               one_json = json.loads(line)
          

          【讨论】:

          • splitlines 对于 JSON Lines 是不安全的,如果存在带有某些字符的字符串,例如 NEL (0x85),它可以在中间拆分 JSON 行。
          • 不知道,已经为我工作了很长时间,但很高兴知道我猜。
          【解决方案7】:

          这扩展了Cohen的答案:

          content_object = s3_resource.Object(BucketName, KeyFileName)
          file_buffer = io.StringIO()
          file_buffer = content_object.get()['Body'].read().decode('utf-8')
          
          json_lines = []
          for line in file_buffer.splitlines():
              j_content = json.loads(line)
              json_lines.append(j_content)
          
          df_readback = pd.DataFrame(json_lines)
          

          这假定整个文件将适合内存。如果它太大,则必须将其修改为分块读取或使用Dask

          【讨论】:

            猜你喜欢
            • 2011-12-22
            • 1970-01-01
            • 1970-01-01
            • 2018-04-15
            • 1970-01-01
            • 2019-08-02
            相关资源
            最近更新 更多