memoryerror 是因 json.load() 将整个 json 文件加载进内存导致,1gb 文件可能占用 3gb+ 内存;应根据文件结构选择 jsonl 逐行解析、ijson.items() 流式读取顶层数组或 ijson.parse() 精准提取字段。

MemoryError 不是代码写错了,是 json.load() 把整个文件塞进内存了。只要文件超过可用 RAM 的 60%,基本就稳崩。
为什么 json.load() 一读就崩
它会把整个 JSON 字符串解析成 Python 对象树,嵌套越深、字段越多,内存占用越夸张——1GB 的 JSON 文件,实际可能吃掉 3GB+ 内存。这不是慢,是直接卡死或被系统 OOM Killer 杀掉。
JSONL 文件:用生成器逐行读 + json.loads()
适用场景:每行一个独立 JSON 对象(如日志、事件流、导出数据),文件后缀常为 .jsonl 或 .ndjson。
- 别用
readlines()—— 它先把全部文本加载进内存,再切行,毫无意义 - 用
for line in file:原生迭代器,每次只读一行 -
json.loads(line.strip())解析单行,立刻处理,不累积 - 确保文件编码是
utf-8,否则json.decoder.JSONDecodeError会掩盖内存问题
示例:
def stream_jsonl(path):
with open(path, 'r', encoding='utf-8') as f:
for line in f:
if line.strip(): # 跳过空行
yield json.loads(line)
单个巨型 JSON 数组:必须用 ijson.items()
适用场景:文件是一个顶层数组,比如 [{...}, {...}, {...}],但数组长度几十万、大小几 GB。
-
pip install ijson(注意:要装在当前 Python 环境) - 必须用
open(..., 'rb')——ijson底层依赖二进制流,传str会报TypeError: a bytes-like object is required - 路径表达式要写对:
ijson.items(file, 'item')表示遍历顶层数组每个元素;如果是data.items.item,就得写'data.items.item' - 别在循环里拼 list:
items = list(ijson.items(...))等于白改
示例:
import ijson
with open('huge.json', 'rb') as f:
parser = ijson.items(f, 'item') # 假设是 [item, item, ...]
for record in parser:
process(record) # 每次只 hold 一个 dict
嵌套结构太深?用 ijson.parse() 精准捞字段
适用场景:你只关心几个字段(比如 user.id、event.timestamp),且结构嵌套多层、数组位置不固定。
-
ijson.parse()返回三元组(prefix, event, value),靠prefix匹配路径 -
prefix是点分路径,比如'users.item.name',不是 JSONPath - 遇到
start_map/end_map可以建临时 dict;遇到string或number才取值 - 别漏
try/except:坏数据、字段缺失、类型错都会触发ValueError或KeyError
示例片段:
for prefix, event, value in ijson.parse(f):
if prefix == 'logs.item.id' and event == 'number':
ids.append(value)
elif prefix == 'logs.item.status' and event == 'string':
statuses.append(value)
真正麻烦的不是“怎么读”,而是你得先搞清文件结构——是 JSONL?是单数组?还是带 wrapper 的对象?看一眼开头几十行,比硬套方案管用得多。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










