node读写大文件
2022-05-18 本文已影响0人
姜治宇
如果读取小文件,我们可以使用fs读取,fs读取文件的时候,是将文件一次性读取到本地内存。而如果读取一个大文件,一次性读取会占用大量内存(Buffer对象),尤其是当我们读写g级的二进制大文件时,使用fs.readFileSync和fs.writeFileSync会报错:
ERROR [ExceptionsHandler] File size (2516230826) is greater than 2 GB
这个时候我们需要用流来解决了。
流是将数据分割成一段一段的读取,可以不会占用太大的内存。比如我们经常使用的gulp建立task任务,还有文件压缩、http中的请求和响应等都是流来实现的。
所有流都是 EventEmitter 的实例,所以不同的流也具有不同的事件,事件也就是告知外界自己自身的工作状态的方式。
流的事件有以下几个:
open - 打开文件
data - 当有数据可读时触发
error - 在读收和写入过程中发生错误时触发
close - 关闭文件
end - 没有更多的数据可读时触发
我们可以将流的读写封装到Promise:
const { rejects } = require('assert');
const fs = require('fs');
const path = require('path');
let srcPath = path.join('D:','big.zip');
let destPath = path.join('E:','zip','tt.zip');
console.log('执行开始...');
handleStream().then(res => {
console.log(res);
if (res && res.code === 200) {
console.log('执行完毕');
}
});
function handleStream() {
return new Promise(resolve => {
//大文件处理,执行过程会阻塞等待
let rs = fs.createReadStream(srcPath, { encoding: 'binary' });
let ws = fs.createWriteStream(destPath, { encoding: 'binary' });
rs.on('data', (chunk) => {
console.log('传输中');
if (!ws.write(chunk)) { //如果还没写就先暂停
console.log('读取暂停');
rs.pause();
}
});
ws.on('drain', () => {
console.log('读取继续');
rs.resume();
});
rs.on('err', (err) => {
rejects({ code: -1, msg: '读取错误' });
});
rs.on('end', () => {
console.log('end');
ws.end();
resolve({ code: 200, data: 'ok' });
});
});
}