停止 Node.js 崩溃:如何使用 15MB RAM 处理 10GB 文件
发布: (2026年5月1日 GMT+8 01:00)
3 分钟阅读
原文: Dev.to
Source: Dev.to
问题:Array.map() 陷阱
大多数开发者会这样处理数据:
const data = JSON.parse(fs.readFileSync('huge-file.json')); // ❌ 此处内存激增
const processed = data.map(record => transform(record)); // ❌ 此处内存翻倍
fs.writeFileSync('output.json', JSON.stringify(processed));这在小文件上可以工作,但它的扩展性是线性的。一个 1 GB 的文件至少需要 2 GB 的 RAM 来同时保存输入和输出。
解决方案:常数内存 (O(1))
Data‑Genie 将数据视为连续流。它不加载整个数组,而是使用 Async Iterators 一次拉取一条记录,进行转换后推送到目标位置。
结果如何?你可以用和处理 100 KB 文件相同的 RAM 来处理 100 GB 的文件。
数据大小对比
| 数据大小 | 朴素方法(基于数组) | Data‑Genie(流式) |
|---|---|---|
| 100 KB | ~10 MB RAM | ~10 MB RAM |
| 100 MB | ~150 MB RAM | ~12 MB RAM |
| 10 GB | 崩溃(OOM) | ~15 MB RAM |
统一 API 适用于不同格式
import { CSVReader, SQLWriter, Job } from '@pujansrt/data-genie';
const reader = new CSVReader('input.csv');
const writer = new SQLWriter(db, 'users');
await Job.run(reader, writer);无论你的数据是 CSV、JSON、Excel、Parquet 还是 SQL 数据库,代码看起来都是一样的。
内置死信队列 (DLQ)
在真实场景中,数据往往“脏”。单条格式错误的记录就可能导致整个任务崩溃。Data‑Genie 包含内置 DLQ,能够自动将失败的记录转存到“毒药”文件,同时主任务继续运行。
import { z } from 'zod';
import { CSVReader, JsonWriter, SchemaValidatingReader } from '@pujansrt/data-genie';
const schema = z.object({
id: z.coerce.number(),
email: z.string().email(),
});
const reader = new CSVReader('input.csv');
const validator = new SchemaValidatingReader(reader, schema)
.setDLQ(new JsonWriter('failed_rows.json'));使用 EventEmitter 实时进度
最新更新将 Job 类改为 EventEmitter,让你可以在不轮询的情况下构建进度条或仪表盘。
import { Job, CSVReader, JsonWriter } from '@pujansrt/data-genie';
const job = new Job(new CSVReader('users.csv'), new JsonWriter('output.json'));
job.on('progress', (metrics) => {
console.log(`Processed ${metrics.recordCount} records...`);
});
await job.run();安装
npm install @pujansrt/data-genie示例用法
import { CSVReader, JsonWriter, Job } from '@pujansrt/data-genie';
const reader = new CSVReader('users.csv');
const writer = new JsonWriter('output.json');
(async () => {
const metrics = await Job.run(reader, writer);
console.log(`Processed ${metrics.recordCount} records in ${metrics.durationMs} ms`);
})();