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

Cat*_*Cat 21 python parsing json large-files

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

{
    "key11": value11,
    "key12": value12,
}
{
    "key21": value21,
    "key22": value22,
}
…
Run Code Online (Sandbox Code Playgroud)

我现在导入它的方式是:

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

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

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

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

njz*_*zk2 28

只需读取每一行并在此时构造一个json对象:

with open(file_path) as f:
    for line in f:
        j_content = json.loads(line)
Run Code Online (Sandbox Code Playgroud)

这样,您加载正确的完整json对象(假设json对象\n中某处或json对象中没有json值),并且在需要时创建每个对象时避免内存问题.

还有这个答案:

/sf/answers/545652061/

  • 没有.`json.loads`失败,因为该行不包含完整的jsonobject.`for line in f`循环在你文件的行上.如果一行不包含完整的jsonobject(例如,如果它在多行上分割),则会失败. (3认同)
  • 或者,也许简明地说,“[json.loads(line) for line in f]”可以使代码位于单行中,并且可以在将来嵌套。 (2认同)

Tjo*_*rie 7

contents = open(file_path, "r").read() 
data = [json.loads(str(item)) for item in contents.strip().split('\n')]
Run Code Online (Sandbox Code Playgroud)


Dan*_*ite 6

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

{
    "key11": 11,
    "key12": 12
}
{
    "key21": 21,
    "key22": 22
}
Run Code Online (Sandbox Code Playgroud)

只需逐行阅读,并随时构建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 = []
Run Code Online (Sandbox Code Playgroud)

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


den*_*son 5

这扩展了科恩的答案:

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)
Run Code Online (Sandbox Code Playgroud)

这假设整个文件适合内存。如果它太大,则必须对其进行修改以分块读取或使用Dask