解析5GB JSON文件应避免json.load()导致内存溢出,推荐三种方案:①用ijson.items()流式解析顶层数组;②用json.JSONDecoder.raw_decode()增量解析拼接JSON;③转为JSONL格式后逐行读取。

直接用 json.load() 读 5GB 的 JSON 文件,基本等于主动触发内存溢出。Python 3.11 没给内置模块加流式能力,必须换思路——核心就两条:要么让文件结构适配流式(如转成 JSONL),要么用第三方库做事件驱动解析。
用 ijson.items() 解析顶层数组中的每个对象
这是最常见也最稳妥的方案,适用于「整个文件是一个大数组,每个元素是独立对象」的结构(例如日志、导出数据)。ijson 不加载全文,而是基于底层 C 解析器逐个提取匹配路径的值。
- 安装:
pip install ijson(注意:它依赖libyajl,Linux/macOS 通常自带,Windows 用户建议用 conda 或预编译 wheel) - 路径写法很关键:
'item'表示数组的每个直接子项;如果数组嵌在data.items下,就得写'data.items.item' - 必须以二进制模式打开文件(
open(..., 'rb')),否则会因编码问题提前中断 - 不要试图在循环里做耗时操作(如写数据库),否则会拖慢解析吞吐;先 yield 出来再批量处理
import ijson
with open('big.json', 'rb') as f:
objects = ijson.items(f, 'item') # ← 路径要和实际结构对得上
for obj in objects:
process(obj) # 这里别放 time.sleep() 或 requests.post()
用 json.JSONDecoder.raw_decode() 做增量解析
当文件不是标准 JSON 数组,而是多个 JSON 对象紧挨着(无分隔符,如 {"a":1}{"b":2}),或者你无法改文件格式时,raw_decode() 是唯一能靠住的内置方案。但它不自动跳过空白或逗号,得自己维护缓冲区。
- 每次读 chunk 后追加到
buffer,然后调用decoder.raw_decode(buffer) - 成功返回
(obj, end_idx),把buffer[end_idx:]留给下一轮;失败说明当前 buffer 不够,继续读 - 必须手动
.lstrip()清掉前导空白,否则下次raw_decode会卡在空格上 - 不能处理字符串内含未转义
{或}的情况——这属于非法 JSON,该修源头
import json
def parse_concatenated_json(file_path):
decoder = json.JSONDecoder()
buffer = ''
with open(file_path, 'r', encoding='utf-8') as f:
while True:
chunk = f.read(8192)
if not chunk:
break
buffer += chunk
while buffer:
try:
obj, idx = decoder.raw_decode(buffer)
yield obj
buffer = buffer[idx:].lstrip() # ← 关键:去掉剩余部分开头的空白
except json.JSONDecodeError:
break
把原始 JSON 改造成 JSONL 格式再按行读
如果文件结构允许(即每个逻辑记录确实是独立对象),强行拆成每行一个 JSON 是最省心的方案。5GB 文件拆完,json.loads(line) 每次只占几 KB 内存,还能用 multiprocessing.Pool.imap() 并行加速。
- 转换脚本本身也要流式处理:不能
json.load()整个源文件,得用ijson或raw_decode先抽出来再写入新文件 - 注意换行符统一为
\n,避免 Windows 的\r\n导致某行多出回车符 - 后续处理时,用
line.strip()再传给json.loads(),防止 BOM 或尾部空格引发错误 - JSONL 不支持注释、尾随逗号、多行字符串——转换前得确认原始数据不含这些
别踩 mmap + ujson 的坑
网上有些方案推荐用 mmap 映射文件 + ujson 解析,听起来高效,但实际非常危险:
-
ujson的loads()仍是全量解析,mmap 只是把磁盘地址映射进虚拟内存,没解决“一次解一个对象”的问题 - 一旦遇到 JSON 格式错误(比如某个对象少了个
}),ujson会直接崩溃,连错误位置都报不出来 - Python 3.11 的
json模块已优化了 C 层解析速度,ujson在多数场景下不再有明显优势,反而增加维护成本 - 真正需要 mmap 的场景是:你已经知道每个对象的字节偏移和长度(比如有索引文件),这时才值得用
最常被忽略的一点:无论选哪种方案,都要在解析前确认文件编码是 UTF-8 且无 BOM。Windows 记事本保存的 JSON 经常偷偷加 BOM,会导致 ijson 报 ValueError: No JSON object could be decoded,而错误信息完全不提示原因。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











