是,用 json.load() 直读大文件会爆内存,因需一次性加载整个嵌套结构;应改用 ijson 流式解析或逐行处理 JSONL,配合安全取值、类型断言及增量更新策略。

用 json.load() 直读大文件会爆内存?别硬扛
直接调 json.load() 读几百MB以上的嵌套JSON,大概率触发 MemoryError 或让系统卡死——它必须把整个树结构一次性载入内存构建嵌套字典/列表。真实场景里,你往往只关心其中某几层字段(比如所有 "user.id" 或某个 "events" 数组里的时间戳),没必要全加载。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 优先改用流式解析:用
ijson库按需提取路径,例如ijson.parse()或ijson.items(file, 'records.item') - 如果数据是 JSON Lines(每行一个 JSON 对象),直接逐行用
json.loads(line),不占额外内存 - 确认文件是否真为单个巨型 JSON:用
head -c 200 large.json看开头,如果是{开头、结尾才},才是单对象;如果是{每行一个,就该当 JSONL 处理
嵌套太深,data['a']['b']['c']['d'] 写到崩溃?用安全取值
手动链式访问嵌套字典,只要中间某层是 None 或缺 key,立刻抛 KeyError 或 TypeError。尤其原始数据字段可能缺失、类型不一致(比如有时是 dict,有时是 null)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 写个简短辅助函数,比如
get_nested(data, 'user.profile.address.city', default='N/A'),内部用reduce(lambda d, k: d.get(k) if isinstance(d, dict) else None, keys, data) - 避免用
eval()或exec()拼路径字符串——不安全且难调试 - 对关键路径做类型断言:取到
city后,显式检查isinstance(city, str),比后期报错更早暴露数据脏
需要修改并保存回嵌套结构?别用 json.dump() 硬覆盖
原文件几十MB,你只改了三处字段,却用 json.dump() 把整个内存对象重写一遍,IO 开销大、易出错、没增量概念。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 若只是小范围更新,考虑用
jq命令行工具配合 Python 调用:subprocess.run(['jq', '.user.active = true', 'input.json'], ...),它原地流式处理,不加载全文 - 如果必须用 Python 写回,先用
json.dumps(obj, separators=(',', ':'))去掉空格,减少体积;再用pathlib.Path('out.json').write_text(...)替代open().write(),省去编码参数纠结 - 永远备份原文件:用
shutil.copy2(input_path, f'{input_path}.bak'),保留修改时间
用 pandas.read_json() 扁平化时字段名撞车?得提前展平
pandas.read_json() 对深度嵌套默认只展开一层,遇到 {"user": {"id": 1, "tags": ["a","b"]}},会生成列 user(值为 dict),不是你想要的 user.id 和 user.tags。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
pd.json_normalize(data, sep='.'),它专为嵌套设计,sep='.'生成user.id这样的扁平列名 - 若含数组字段(如
"orders": [{"id":1}, {"id":2}]),加参数record_path='orders'提取为独立 DataFrame,再用meta带上父级字段 - 注意
json_normalize不支持流式,仍需先加载进内存——大文件慎用,先用ijson抽出目标片段再归一化
print(type(data.get('user', {})),比硬猜结构省两小时。


















