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

Node.js如何逐行读取大型JSON文件(无需全量加载到内存)

Node.js 大体积JSON文件流式处理+多文件并发读取方案

处理GB级大JSON文件的核心思路是放弃全量加载到内存的模式,使用流式读取逐段/逐行解析,配合Promise的并发能力即可实现多文件同时处理,以下分别给出原生实现和第三方库可选方案。

原生实现方案(无需第三方依赖)

该方案适用于行存储格式的JSON文件(也叫JSON Lines,每行对应一个完整的JSON对象,日常日志、结构化导出文件大多是这种格式),基于Node.js内置的fs、readline模块实现,内存占用仅和单次读取的缓冲区、匹配结果数量有关,500MB文件运行时内存占用可控制在100MB以内。

单文件流式搜索实现

你提供的代码已经符合流式处理的核心逻辑,这里做了小优化,删除了不必要的输出流实例:

const fs = require('fs');
const readline = require('readline');

const searchStream = (path, text = '') => new Promise((resolve, reject) => {
  const inStream = fs.createReadStream(path, { encoding: 'utf8' });
  const rl = readline.createInterface({ 
    input: inStream, 
    crlfDelay: Infinity // 兼容所有换行符格式
  });
  const result = [];
  let count = 0;
  const regEx = new RegExp(text, 'i');

  rl.on('line', (line) => {
    if (!line) return;
    // 若需要匹配JSON属性,可在此处先执行 const row = JSON.parse(line) 再判断
    if (line.search(regEx) >= 0) {
      count++;
      result.push(line);
    }
  });

  rl.on('close', () => resolve({ path, result, count }));
  rl.on('error', (err) => reject({ path, error: err }));
});

多文件并发调用

直接使用Promise.all即可实现并发,若文件数量超过20个,建议加并发池限制最大同时读取的数量,避免IO占满影响性能:

// 无并发限制版本,适合文件数量较少的场景
const batchSearchFiles = async (filePaths, searchText) => {
  const searchResults = await Promise.all(
    filePaths.map(filePath => searchStream(filePath, searchText))
  );
  return searchResults;
};

// 带并发限制版本,适合文件数量较多的场景,默认最大并发数为3
const promisePool = async (tasks, poolSize = 3) => {
  const result = [];
  const executing = [];
  for (const task of tasks) {
    const p = Promise.resolve().then(() => task());
    result.push(p);
    if (poolSize <= tasks.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1));
      executing.push(e);
      if (executing.length >= poolSize) {
        await Promise.race(executing);
      }
    }
  }
  return Promise.all(result);
};

const batchSearchWithLimit = async (filePaths, searchText, limit = 3) => {
  const tasks = filePaths.map(filePath => () => searchStream(filePath, searchText));
  return promisePool(tasks, limit);
};

特殊场景适配(单一大JSON对象)

如果你的文件是单个完整的JSON对象(不是每行一个JSON的格式),逐行读取会出现JSON截断无法解析的问题,推荐使用第三方库JSONStream做流式节点解析,仅提取你需要的JSON字段,不需要全量加载整个文件:

const JSONStream = require('JSONStream');
const fs = require('fs');

// 示例:提取JSON中rows数组下的所有元素,逐节点处理
const parseBigSingleJSON = (filePath, matchPath = 'rows.*') => new Promise((resolve, reject) => {
  const matchResults = [];
  fs.createReadStream(filePath)
    .pipe(JSONStream.parse(matchPath)) // 按JSON路径匹配需要提取的节点
    .on('data', node => {
      // 按需处理匹配到的节点
      matchResults.push(node);
    })
    .on('end', () => resolve(matchResults))
    .on('error', reject);
});

注意事项

  • 流式处理过程中不要把所有行/节点全量存入结果数组,仅保留符合要求的内容,否则内存占用依然会随文件体积上涨
  • 可以给createReadStream传递highWaterMark参数调整缓冲区大小,默认是64KB,大文件场景可调整为256KB或512KB提升读取效率
  • 解析JSON时建议加try catch包裹,避免个别行格式错误导致整个进程崩溃

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 21:45:07