You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Django构建JSON服务读取1GB大文件触发MemoryError求助

解决Django读取大JSON文件的MemoryError问题

嘿,这个问题太常见了——你用json.load()直接把1GB的JSON全塞进内存,不爆错才怪呢!Python解析JSON时会把整个文件转换成内存里的字典或列表,这个过程的内存开销比原始文件大很多,1GB的文件可能要占2-3GB甚至更多内存,直接把程序撑爆了。

给你两个实用的解决方案,按需选择:

方案一:直接返回文件流(最简单,无需解析)

如果不需要对JSON内容做任何修改,只是原样返回给客户端,那直接用Django的FileResponse就行,它会把文件以流的形式发送,完全不占内存:

from django.http import FileResponse

def homepage(request):
    # 用rb模式打开,确保二进制流传输
    with open("file.json", 'rb') as f:
        return FileResponse(f, content_type='application/json')

FileResponse会自动处理文件的关闭和分块传输,比你自己手动读文件安全多了。

方案二:流式解析并返回(需要处理内容时用)

如果必须要解析JSON内容(比如过滤、修改部分数据),那用ijson这个库来流式解析,它会逐块读取JSON,而不是一次性加载整个文件。

首先安装依赖:

pip install ijson

然后修改视图代码,以JSON数组为例(大部分大JSON都是数组结构):

import ijson
import json
from django.http import StreamingHttpResponse

def homepage(request):
    def stream_processed_json():
        # 先返回数组的开头括号
        yield '['
        first_item = True
        
        with open("file.json", "rb") as f:
            # 'item'对应JSON数组里的每个元素,如果你JSON是根对象,要改这里的路径
            for item in ijson.items(f, 'item'):
                # 这里可以加你的处理逻辑,比如过滤、修改item
                # 示例:if item['status'] == 'active':
                if not first_item:
                    # 非第一个元素前加逗号
                    yield ','
                yield json.dumps(item)
                first_item = False
        
        # 最后返回数组的结尾括号
        yield ']'
    
    # 返回流式响应,指定JSON类型
    return StreamingHttpResponse(stream_processed_json(), content_type='application/json')

这个方法每次只在内存里存一个JSON元素,内存占用极低,就算是10GB的JSON也能轻松处理。如果你的JSON是根对象(不是数组),可以用ijson.kvitems()来逐个读取键值对,然后拼接成JSON对象返回。

额外提醒

  • 永远不要用json.load()json.loads()处理大文件,这两个方法都会把整个内容加载到内存,绝对会爆内存。
  • 如果用FileResponse,要确保文件路径正确,并且Django进程有读取该文件的权限。

内容的提问来源于stack exchange,提问作者Halim

火山引擎 最新活动