可读流
可读流基本使用
const fs = require('fs')
let ReadStream = require('ReadStream')
let rs = new ReadStream('./1.txt',{
flags:'r', // 当前需要什么操作
encoding:null, // 默认是buffer
highWaterMark:2, // 内部会创建 64k大的buffer
mode:438, // 操作权限 读(4) 写(2) 执行(1)
autoClose:true, // 是否自动关闭
start:0,
end:4 // 包前又包后
})
// 默认流的模式是暂停模式
rs.on('open',function(fd){
console.log('文件打开触发open事件',fd)
})
let arr = []
rs.on('data',function(data){
console.log(data);
arr.push(data);
this.pause() // 暂停
})
setInterval(()=>{
rs.resume() // 恢复读取
},1000)
rs.on('end',function(){
console.log('文件读取完毕')
console.log(Buffer.concat(arr).toString())
})
rs.on('close',function(){
console.log('文件关闭')
})
可读流代码实现
const EventEmitter = require('events');
const fs = require('fs')
class ReadStream extends EventEmitter{
constructor(path,options={}){
super()
this.path = path;
this.flags = options.flags || 'r'
this.encoding = options.encoding || null
this.highWaterMark = options.highWaterMark || 64*1024
this.mode = options.mode || 438
this.autoClose = options.autoClose || true
this.start = options.start || 0
this.end = options.end
this.flowing = null // 默认是暂停模式
this.offset = 0; // 偏移量
// 创建实例的时候 默认调用open
this.open()
this.on('newListener',(type)=>{
// 当用户监听 data事件的时候 就开始读取文件
if(type==='data'){
this.flowing = true;
this.read();
}
})
}
pipe(ws){
this.on('data',(chunk)=>{
let flag = ws.write(chunk);
if(!flag){
this.pause();
}
});
ws.on('drain',()=>{
this.resume();
})
}
open(){
fs.open(this.path,this.flags,(err,fd)=>{
this.fd = fd;
this.emit('open',this.fd)
})
}
read(){
// 因为open是异步的 所以调用read的时候可能 没有取到fd
if(typeof this.fd !=='number'){
// 订阅一个事件 当open触发的时候重新调用read方法
return this.once('open',this.read)
}
let howMuchToRead = this.end ? Math.min(this.highWaterMark,this.end - this.start + 1 - this.offset) : this.highWaterMark
let buffer = Buffer.alloc(howMuchToRead)
fs.read(this.fd,buffer,0,howMuchToRead,offset,(err,bytesRead)=>{
this.offset += bytesRead;
if(bytesRead > 0){
this.emit('data',buffer)
this.flowing && this.read();
}else{
this.emit('end')
this.close()
}
})
}
close(){
if(this.autoClose){
fs.close(this.fd,()=>{
this.emit('close')
})
}
}
pause(){
this.flowing = false
}
resume(){
this.flowing = true;
this.read()
}
}
module.exports = ReadStream
可写流
可写流基本使用
const fs = require('fs')
const WriteStream = require('writeStream')
let ws = new WriteStream('./1.txt',{
highWaterMark:3,// 表示预期占用几个内存
encoding:'utf8',// 写入的编码
start:0, // 从文件的第0个位置开始写入
mode:438,
flags:'w' // 默认操作是可写
})
let index = 0;
function write(){// 可写流写入的数据只能是字符串或者buffer
let flag = true;
while(index<10 && flag){
// flag 代表highWaterMark是否有空余
flag = ws.write(index+'')
console.log(flag)
index++;
}
}
write();
ws.on('drain',function(){
console.log('干了')
write()
})
ws.on('close',function(){
console.log('close')
})
可写流代码实现
let EventEmitter = require('events');
let fs = require('fs');
class WriteStream extends EventEmitter{
constructor(path,options = {}){
super();
this.path = path;
this.highWaterMark = options.highWaterMark || 16*1024
this.encoding = options.encoding || 'utf8';
this.start = options.start || 0;
this.mode = options.mode || 0o666;
this.flags = options.flags || 'w';
// 先打开文件
this.open();
// 缓存区
this.cache = [];
this.writing = false; // 判断是否正在被写入
this.len = 0; // 缓存区的大小
this.needDrain = false; // 是否触发drain事件
this.offset = this.start; // offset 表示每次写入的偏移量
}
open(){
fs.open(this.fd,this.flags,(err,fd)=>{
this.fd = fd;
this.emit('open',fd)
})
}
write(chunk,encoding=this.encoding,callback){
// 此时这里面 用户调用write方法时 需要判断当前是否正在写入,如果正在写入 放到缓存中,如果不是正在写入 需要把他真正的像文件里写入
chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)
this.len+=chunk.length// 统计写入数据的个数
let flag = this.len < this.highWaterMark;
this.needDrain = !flag;// 正好是相反操作 只有当前写入的内容>=了highWaterMark才会触发
if(this.writing){ // 当前是否正在写入
// 将除了第一次真实像文件中写入的其他都放到缓存中
this.cache.push({
chunk,
encoding,
callback
})
}else{
this.writing = true;
this._write(chunk,encoding,()=>{
callback && callback();// 先执行自己的成功操作
this.clearBuffer();
})
}
return flag;
}
// 核心的写入方法
_write(chunk,encoding,clearBuffer){
if(typeof this.fd!=='number'){
return this.once('open',()=>this._write(chunk,encoding,clearBuffer))
}
fs.write(this.fd,chunk,0,chunk.length,this.offset,(err,written)=>{
this.offset += written;
this.len -= written;
clearBuffer()
})
}
clearBuffer(){
// 去缓存中取
let obj = this.cache.shift();
if(obj){ // 需要写入
this._write(obj.chunk,obj.encoding,()=>{
obj.callback && obj.callback();
this.clearBuffer();
});
}else{
if(this.needDrain){
this.needDrain = false; // 下一次需要重新判断是否需要触发drain事件
this.writing = false; //告诉下一次调用write 应该像文件中写入
this.emit('drain');
}
}
}
close(){
fs.close(this.fd,()=>{
this.emit('close')
})
}
end(chunk,encoding){ // end 方法就是如果传递参数 就需要调用this._write方法
if(chunk){
// chunk = Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk);
// 先讲写入的缓存 强制清空 在去写入end方法中的内容 在关闭文件
return this.write(chunk,encoding,()=>{
this.close()
})
}
this.close();
}
}
module.exports = WriteStream;
基于stream实现可读和可写流
读流
提供_read方法,调用push
let {Readable,Writable} = require('stream')
class MyRead extends Readable{
_read(){
this.push('1');
this.push(null)
}
}
let mr = new MyRead();
mr.on('data',function(chunk){
console.log(chunk)
})
mr.on('end',function(chunk){
console.log('end')
})
写流
提供_write方法,调用clearBuffer
class MyWrite extends Writable{
_write(chunk,encoding,clearBuffer){
console.log(chunk,'----')
clearBuffer();
}
}
let myWrite = new MyWrite();
myWrite.write('123');