如何从大文件中读取行分隔的 JSON(逐行)

问题描述 投票:0回答:8

我正在尝试加载一个大文件(大小为 2GB),其中充满 JSON 字符串,并以换行符分隔。例如:

{
    "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
对象?谢谢!

python json parsing large-files
8个回答
45
投票

此时只需读取每一行并构造一个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


11
投票
contents = open(file_path, "r").read() 
data = [json.loads(str(item)) for item in contents.strip().split('\n')]

7
投票

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

{
    "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 回调方法。


5
投票

这扩展了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


2
投票

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

splitlines

代码:

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

1
投票

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

但是,在多个

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
,并解析整个文件:-)。


0
投票

jq python 库可以快速处理此类情况。

这是我项目中的一个示例。在我的案例中,我从其他地方获得了文件对象。

import jq

raw = file.read().decode("utf-8")
for row in iter(jq.compile(".").input(text=raw)):
  print(row)

并且可以这样安装依赖项:

pip install jq

查看 jq,这是在命令行或代码中查询 json 对象的简单方法。


-1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.