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

如何使用Node.js读取并处理超过2GB的大型JSON文件?

碰到这种大文件读取的问题太常见了——你用的fs.readFile会把整个文件一次性塞进内存,而Node.js默认对单个文件的读取内存限制是2GiB,你的3GB文件直接超了,所以才会抛出ERR_FS_FILE_TOO_LARGE这个错误。

要解决这个问题,核心思路是不要一次性加载整个文件到内存,而是用流式处理逐行/逐个元素解析,或者回到MongoDB直接预处理数据,下面是几种实用的方案:

解决方案

方法1:用JSONStream流式解析(推荐)

JSONStream是专门处理大JSON文件的第三方库,它可以把JSON数组拆成单个元素逐个输出,完全不用加载整个文件到内存。

步骤:

  1. 首先安装依赖:
npm install jsonstream
  1. 编写处理代码:
const fs = require('fs');
const JSONStream = require('JSONStream');

// 输入文件路径
const inputPath = '/Users/chx/Downloads/dump/off/products.json';
// 输出转换后的文件路径
const outputPath = '/Users/chx/Downloads/dump/off/transformed_products.json';

const readStream = fs.createReadStream(inputPath, 'utf8');
const writeStream = fs.createWriteStream(outputPath);

// 先写入JSON数组的开头
writeStream.write('[');
let isFirstItem = true;

// 解析JSON数组的每个元素
readStream
  .pipe(JSONStream.parse('*')) // '*'表示匹配数组里的每个元素
  .on('data', (product) => {
    // 这里实现你的nutrients命名转换逻辑
    const transformedProduct = {
      id: product.id,
      product_name: product.product_name,
      nutrients: transformNutrientNames(product.nutrients)
    };

    // 处理JSON数组的逗号分隔(第一个元素前面不加逗号)
    if (!isFirstItem) {
      writeStream.write(',');
    }
    isFirstItem = false;

    // 写入转换后的对象
    writeStream.write(JSON.stringify(transformedProduct));
  })
  .on('end', () => {
    // 写入JSON数组的结尾
    writeStream.write(']');
    writeStream.end();
    console.log('所有数据处理完成!');
  })
  .on('error', (err) => {
    console.error('处理过程中出错:', err);
  });

// 示例转换函数,根据你的数据库规则修改
function transformNutrientNames(nutrients) {
  const transformed = {};
  // 比如把原字段名从 camelCase 转成 snake_case,或者映射到你需要的字段
  for (const [oldKey, value] of Object.entries(nutrients)) {
    // 示例:将"energy"改为"calories","fat"改为"total_fat"
    switch (oldKey) {
      case 'energy':
        transformed.calories = value;
        break;
      case 'fat':
        transformed.total_fat = value;
        break;
      case 'saturated-fat':
        transformed.saturated_fat = value;
        break;
      // 其他营养成分字段...
      default:
        // 如果没有匹配的规则,保留原字段或自定义处理
        transformed[oldKey] = value;
    }
  }
  return transformed;
}

方法2:原生Node.js readline手动解析(无需第三方库)

如果不想引入第三方依赖,可以用Node.js内置的readline模块逐行读取,手动处理JSON数组的结构:

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

const inputPath = '/Users/chx/Downloads/dump/off/products.json';
const outputPath = '/Users/chx/Downloads/dump/off/transformed_products.json';

const rl = readline.createInterface({
  input: fs.createReadStream(inputPath, 'utf8'),
  crlfDelay: Infinity // 识别所有换行符
});

const writeStream = fs.createWriteStream(outputPath);
writeStream.write('[');
let isFirstItem = true;
let isInsideArray = false;

rl.on('line', (line) => {
  const trimmedLine = line.trim();
  
  // 跳过JSON数组的开头和结尾标记
  if (trimmedLine === '[') {
    isInsideArray = true;
    return;
  }
  if (trimmedLine === ']') {
    isInsideArray = false;
    return;
  }
  if (!isInsideArray) return;

  // 去掉行尾的逗号(MongoDB导出的JSON每行结尾会有逗号)
  const productStr = trimmedLine.replace(/,$/, '');
  
  try {
    const product = JSON.parse(productStr);
    const transformedProduct = {
      id: product.id,
      product_name: product.product_name,
      nutrients: transformNutrientNames(product.nutrients)
    };

    if (!isFirstItem) {
      writeStream.write(',');
    }
    isFirstItem = false;
    writeStream.write(JSON.stringify(transformedProduct));
  } catch (err) {
    console.error('解析某行出错:', err);
  }
});

rl.on('close', () => {
  writeStream.write(']');
  writeStream.end();
  console.log('处理完成!');
});

// 复用上面的transformNutrientNames函数
function transformNutrientNames(nutrients) {
  // 你的转换逻辑...
}

方法3:直接在MongoDB中预处理(最省心)

既然你的数据是从MongoDB导出的,不如直接在数据库里完成nutrients的命名转换,再导出干净的文件,这样完全不用处理大JSON:

在MongoDB Compass中打开products集合,创建以下聚合管道并运行:

[
  {
    $project: {
      id: 1,
      product_name: 1,
      nutrients: {
        // 这里写你的字段映射规则,比如:
        calories: "$nutrients.energy",
        total_fat: "$nutrients.fat",
        saturated_fat: "$nutrients.saturated-fat",
        protein: "$nutrients.protein",
        carbohydrates: "$nutrients.carbohydrates"
        // 其他需要转换的字段...
      }
    }
  },
  {
    $out: "transformed_products" // 将结果输出到新集合
  }
]

运行完成后,新集合transformed_products里就是已经转换好的数据,直接导出JSON即可,MongoDB处理大集合的效率比Node.js高很多。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 15:22:35