You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js处理10GB/850MB大JSON文件卡顿报错解决方案咨询

大体积JSON订单文件处理方案

核心问题原因

你之前的两种实现都属于全量加载模式:

  1. 第一次用JSONStream时配置了parse('*'),会将整个JSON结构完整解析后存入orders数组,等于还是把全部100万+订单对象加载到内存,自然会触发卡顿
  2. 第二次直接拼接整个文件流到字符串再调用JSON.parse,850MB的文本长度超出了V8引擎的字符串最大长度限制,因此抛出RangeError: Invalid string length错误

正确实现方案

用流式JSON解析的正确姿势是只匹配orders数组下的单个订单节点,每解析完成一个订单就处理,处理完直接丢弃不保留全量数据,内存占用可以稳定在几十MB级别。
首先安装依赖:

npm install JSONStream event-stream

1. 统计订单总数量

仅计数不存储订单对象,内存占用极低:

const fs = require('fs');
const JSONStream = require('JSONStream');
const es = require('event-stream');

function countOrders(filePath) {
  return new Promise((resolve, reject) => {
    let orderCount = 0;
    fs.createReadStream(filePath, { encoding: 'utf8' })
      // 仅匹配orders数组下的每个子元素,逐订单解析
      .pipe(JSONStream.parse('orders.*'))
      .pipe(es.mapSync(() => {
        orderCount++;
      }))
      .on('end', () => resolve({ count: orderCount }))
      .on('error', (err) => reject(err));
  });
}

2. 按订单ID查找对应订单

找到匹配项后直接终止文件读取,不需要遍历整个文件:

function findOrderById(filePath, targetOrderId) {
  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(filePath, { encoding: 'utf8' });
    let matchedOrder = null;

    readStream
      .pipe(JSONStream.parse('orders.*'))
      .pipe(es.mapSync((order) => {
        if (order.id === targetOrderId) {
          matchedOrder = order;
          // 找到目标直接销毁流,停止后续文件读取
          readStream.destroy();
        }
      }))
      // 销毁流会触发close事件,结束后返回结果
      .on('close', () => resolve(matchedOrder))
      // 遍历完全部文件仍未找到也返回结果
      .on('end', () => resolve(matchedOrder))
      .on('error', (err) => reject(err));
  });
}

3. 按起始ID和数量限制获取订单集合

取够指定数量后直接终止读取:

function getOrderList(filePath, startOrderId, limit) {
  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(filePath, { encoding: 'utf8' });
    const resultList = [];
    // 如果未传起始ID,直接从第一个订单开始取
    let isStart = startOrderId == null;

    readStream
      .pipe(JSONStream.parse('orders.*'))
      .pipe(es.mapSync((order) => {
        if (isStart) {
          resultList.push(order);
          // 取够指定数量直接终止读取
          if (resultList.length >= limit) readStream.destroy();
          return;
        }
        // 匹配到起始ID后开始收集
        if (order.id === startOrderId) {
          isStart = true;
          resultList.push(order);
          if (resultList.length >= limit) readStream.destroy();
        }
      }))
      .on('close', () => resolve(resultList))
      .on('end', () => resolve(resultList))
      .on('error', (err) => reject(err));
  });
}

优化建议

如果需要多次执行查询操作,建议首次遍历文件时构建ID与文件偏移量的索引表,后续查询可以直接跳转到对应位置读取,无需每次都遍历整个文件,查询效率可以提升百倍以上。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 07:36:02