NodeJS读写(同步异步、流式、分片策略)
Node.js文件读写操作核心API及模式详解
一、基础文件读写API
-
同步操作
• API:fs.readFileSync()
/fs.writeFileSync()
• 特点:阻塞主线程,适合处理小文件(<1MB)或启动初始化
• 示例:
const data = fs.readFileSync('config.json', 'utf8'); fs.writeFileSync('backup.json', data);
-
异步回调
• API:fs.readFile()
/fs.writeFile()
• 特点:非阻塞,需通过回调处理结果,易引发“回调地狱”
• 示例:
fs.readFile('log.txt', (err, data) => {if (err) throw err;fs.writeFile('log_backup.txt', data, () => {}); });
-
Promise形式
• API:fs.promises.readFile()
/fs.promises.writeFile()
• 特点:配合
async/await
使用,代码结构更清晰• 示例:
async function processFile() {const data = await fs.promises.readFile('data.csv');await fs.promises.writeFile('processed.csv', data); }
二、同步与异步模式对比
维度 | 同步操作 | 异步操作 |
---|---|---|
执行方式 | 阻塞主线程 | 非阻塞,后台I/O线程池处理 |
适用场景 | 配置文件加载、初始化数据 | 大文件处理、高并发请求 |
内存占用 | 直接加载全量数据 | 分块处理,内存压力小 |
错误处理 | try/catch 捕获 | 回调参数或Promise链式捕获 |
性能影响 | 导致界面卡顿 | 保持应用响应流畅 |
三、流式操作(处理大文件核心方案)
-
读取流
• API:fs.createReadStream()
• 特性:分块读取(默认64KB/块),支持
highWaterMark
调整缓冲区• 示例:
const readStream = fs.createReadStream('video.mp4', { highWaterMark: 128*1024 }); readStream.on('data', (chunk) => { /* 处理数据块 */ });
-
写入流
• API:fs.createWriteStream()
• 特性:自动处理背压,支持追加模式
• 示例:
const writeStream = fs.createWriteStream('output.log', { flags: 'a' }); writeStream.write('日志内容\n');
-
管道流
• API:readStream.pipe(writeStream)
• 应用:实现文件复制、数据压缩等链式操作
• 示例(GZIP压缩):
fs.createReadStream('data.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('data.txt.gz'));
四、高级技巧
-
内存映射
• API:fs.open()
+fs.read()
• 场景:高频随机访问大文件(如数据库索引)
• 优势:直接操作内存缓冲区,避免多次磁盘I/O
const fd = fs.openSync('large.bin', 'r'); const buffer = Buffer.alloc(1024); fs.read(fd, buffer, 0, 1024, 0);
-
错误处理规范
• 同步操作必须用try/catch
包裹• 异步流操作需监听
error
事件:readStream.on('error', (err) => console.error('读取失败:', err)); writeStream.on('error', (err) => console.error('写入失败:', err));
-
性能优化参数
•highWaterMark
:调整流缓冲区大小(如设置128MB分块)•
autoClose
:流结束后自动关闭文件描述符•
emitClose
:确保流关闭事件触发fs.createReadStream('data.bin', { highWaterMark: 128*1024*1024 });
五、模式选择建议
-
小文件(<10MB):
• 优先使用fs.promises
的Promise API• 同步操作仅限程序启动阶段
-
中型文件(10MB~1GB):
• 采用流式分块处理• 结合
pipeline
方法提升吞吐量 -
超大文件(>1GB):
• 必须使用流式操作• 结合内存映射+Worker线程并行处理
通过合理选择API和模式,可显著提升Node.js文件处理性能。对于日志分析、视频处理等场景,推荐优先采用流式+管道组合方案。
以下是基于不同文件规模选择 Node.js 文件操作模式的实例代码及解析:
一、小文件(<10MB)
- Promise API 异步读写
const fs = require('fs').promises;// 读取并复制小文件
async function processSmallFile() {try {const data = await fs.readFile('config.json', 'utf8');await fs.writeFile('config_backup.json', data);console.log('小文件操作完成');} catch (err) {console.error('错误:', err.message);}
}
processSmallFile();
特点:
• 使用 fs.promises
的 Promise 接口,代码简洁
• 适合配置文件、初始化数据等场景
- 同步操作(仅限启动阶段)
const fs = require('fs');try {const config = fs.readFileSync('env.prod', 'utf8');fs.writeFileSync('env.backup', config);console.log('启动阶段同步操作完成');
} catch (err) {console.error('同步错误:', err.message);
}
注意:同步操作会阻塞事件循环,仅建议在程序初始化时使用
二、中型文件(10MB~1GB)
- 流式分块处理 + pipeline
const fs = require('fs');
const { pipeline } = require('stream/promises');
const zlib = require('zlib');// 流式压缩文件
async function processMediumFile() {try {await pipeline(fs.createReadStream('data.log', { highWaterMark: 128 * 1024 }), // 128KB分块zlib.createGzip(),fs.createWriteStream('data.log.gz'));console.log('中型文件压缩完成');} catch (err) {console.error('流处理错误:', err);}
}
processMediumFile();
优化点:
• pipeline
自动处理背压和错误传播
• highWaterMark
调整缓冲区大小提升吞吐量
- 逐行处理日志文件
const fs = require('fs');
const readline = require('readline');const rl = readline.createInterface({input: fs.createReadStream('access.log'),crlfDelay: Infinity
});rl.on('line', (line) => {if (line.includes('ERROR')) {fs.appendFileSync('errors.log', line + '\n');}
});
rl.on('close', () => console.log('日志分析完成'));
适用场景:日志过滤、CSV 数据处理等
三、超大文件(>1GB)
- 流式操作 + 内存映射
const fs = require('fs');
const { Worker, isMainThread } = require('worker_threads');// 主线程:分片处理
if (isMainThread) {const CHUNK_SIZE = 512 * 1024 * 1024; // 512MB分片const fd = fs.openSync('huge_dataset.bin', 'r');const stats = fs.fstatSync(fd);for (let i = 0; i < stats.size; i += CHUNK_SIZE) {new Worker(__filename, {workerData: { fd, offset: i, chunkSize: CHUNK_SIZE }});}
}
// Worker线程:内存映射读取
else {const { fd, offset, chunkSize } = workerData;const buffer = Buffer.alloc(chunkSize);fs.read(fd, buffer, 0, chunkSize, offset, (err) => {if (err) throw err;processBufferData(buffer); // 自定义处理逻辑fs.closeSync(fd);});
}
核心技术:
• 内存映射减少磁盘 I/O 次数
• Worker 线程实现并行处理
- 分块流式备份
const fs = require('fs');async function backupLargeFile() {const readStream = fs.createReadStream('big_db.dump', {highWaterMark: 256 * 1024 * 1024 // 256MB缓冲区});const writeStream = fs.createWriteStream('backup.dump');readStream.on('data', (chunk) => {if (!writeStream.write(chunk)) {readStream.pause(); // 背压控制}});writeStream.on('drain', () => readStream.resume());
}
backupLargeFile();
特点:
• 手动背压控制保障内存安全
• 适合数据库备份等场景
关键参数对比表
文件规模 | 核心 API | 内存占用 | 适用场景 |
---|---|---|---|
<10MB | fs.promises | 全量加载 | 配置文件、初始化数据 |
10MB~1GB | createReadStream + pipeline | 分块缓冲 | 日志分析、CSV 处理 |
>1GB | 内存映射 + Worker 线程 | 分片映射 | 大数据处理、视频转码 |
最佳实践建议:
- 流式操作始终添加
error
事件监听 - 通过
highWaterMark
按硬件配置调整缓冲区 - 超过 2GB 文件必须使用分片策略