node ReadStream 实现
fs.createReadStream 继承自 stream模块
const fs = require('fs');
const EventEmitter = require('events');
class ReadStream extends EventEmitter {
constructor(path, options = {}) {
super();
this.path = path;
this.encoding = options.encoding || 'utf8';
this.flags = options.flags || 'r';
this.mode = options.mode || 0o666;
this.start = options.start || 0;
this.pos = this.start;
this.end = options.end;
this.highWaterMark = options.highWaterMark || 16 * 1024;
this.autoClose = options.autoClose || true;
this.buffers = [];
this.fd = undefined;
this.flowing = false;
this.length = 0;
this.open();
this.on('newListener', (type, event) => { // 监听newListenergkwr,一旦绑定新事件就会触发
if (type === 'data') { // 如果监听了data事件,则进行数据读取,并将流动模式改为true
this.read();
this.flowing = true;
}
})
}
open() {
fs.open(this.path, this.flags, this.mode, (err, fd) => {
if (err) {
if (this.autoClose) {
this._destory();
}
this.emit('error', err);
} else {
this.fd = fd;
this.emit('open', fd);
}
})
}
pause() {
// 暂停读取
this.flowing = false;
}
resume() {
// 恢复读取
this.flowing = true;
this.read();
}
// 进行管道传输
pipe(ws) {
if (typeof this.fd !== 'number') {
this.open();
}
this.on('data', data => {
let flag = ws.write(data);
if (!flag) {
this.pause();
// console.log(this.pause)
}
})
// console.log('read: ' + this.fd)
// console.log('wrte: ' + ws.fd)
ws.on('drain', () => {
// console.log(this)
// this.resume();
// console.log(this.resume)
})
}
read() {
if (typeof this.fd !== 'number') {
// 判断文件是否已经打开,如果没有则绑定open事件,当文件打开后则再次进行read
return this.once('open', () => this.read());
}
this._read();
}
_read() {
// 计算要读取的长度,如果此时剩下的读取长度小于highWaterMark就用end结束长度减去当前的pos偏移量
let howMuchRead = this.end ? Math.min(this.end - this.pos, this.highWaterMark) : this.highWaterMark;
// console.log(this.end, this.end - this.pos + 1)
let buffer = Buffer.alloc(howMuchRead); // 分配指定大小buffer数据传输区
fs.read(this.fd, buffer, 0, howMuchRead, this.pos, (err, readBytes) => {
if (err) {
this.emit('error', err);
this._destory();
} else {
if (readBytes) {
this.pos += readBytes;
this.emit('data', this.encoding === 'utf-8' ? buffer.slice(0, readBytes).toString() : buffer.slice(0, readBytes));
if (this.flowing) { // 如果是flowing流动模式,则继续读取
this._read();
}
} else {
// 数据读取完毕,触发end事件,并关闭fs文件读取通道
this.emit('end');
this._destory();
}
}
})
}
// 销毁或关闭fs文件读取通道
_destory() {
fs.close(this.fd, (err) => {
if (err) throw err;
this.emit('close');
})
}
}
module.exports = ReadStream;
// 正面是测试代码
// const rs = new ReadStream('stream/2.writable.txt', {
// highWaterMark: 3,
// encoding: 'utf-8',
// end: 13
// });
// rs.on('open', () => {
// console.log('file open~');
// })
// rs.on('data', data => {
// console.log(data);
// rs.pause();
// })
// rs.on('end', () => {
// console.log('read end');
// });
// rs.on('close', () => {
// console.log('file close');
// })
// setInterval(() => {
// rs.resume();
// },500)