简明writeStream实现
生活随笔
收集整理的這篇文章主要介紹了
简明writeStream实现
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
Pro
一個(gè)createWriteStream的簡單實(shí)現(xiàn),以求能增加對可寫流的理解與應(yīng)用。
參數(shù)配置
/*** createWriteStream* @param1 path* @param2 options*/ let fs = require('fs'); let ws = fs.createWriteStream('./1.txt',{flags:'w'//文件的打開模式,mode:0o666//文件的權(quán)限設(shè)置,encoding:'utf8'//寫入文件的字符的編碼,highWaterMark:3//最高水位線,start:0 //寫入文件的起始索引位置 ,autoClose:true//是否自動(dòng)關(guān)閉文檔 }) 復(fù)制代碼createWriteStream類的實(shí)例化
- 實(shí)例化一個(gè)createWriteStream類
- 將path,options掛載在createWriteStream的實(shí)例上,除此之外再在實(shí)例上掛載以下屬性
- self.fd=null:文件打開后返回的文件描述符
- self.pos=self.start:用于表示文件真正寫入時(shí)的指針位置
- self.Buffer=[]:用來表示文件的緩沖區(qū)
- self.len=null:用來表示緩沖區(qū)此時(shí)的大小
- self.isWriting=false:用來表示是否正在真正寫入文件
- 調(diào)用open方法,打開文件(發(fā)射open事件)
- 將path,options掛載在createWriteStream的實(shí)例上,除此之外再在實(shí)例上掛載以下屬性
實(shí)例write方法的執(zhí)行流程
- wirte方法接收三個(gè)參數(shù),chunk要寫入的內(nèi)容,encoding要進(jìn)行的,cb回調(diào)函數(shù)。
- write執(zhí)行流程:
- 判斷傳入的chunk是否為buffer,如果不是,則轉(zhuǎn)換成buffer,用于轉(zhuǎn)化編碼依據(jù)傳入的encoding參數(shù)。
- 更新Buffer緩沖區(qū)的len長度,讓len加上該次chunk的長度
- 判斷l(xiāng)en是否已經(jīng)超過highWaterMark,將值存入flag
- 判斷是否處于isWriting狀態(tài):
- 是,則先加chunk寫入實(shí)例對象下的Buffer緩沖區(qū)。
- 否,更新isWriting,接將參數(shù)傳遞給實(shí)例下的_write方法寫入文件
- 返回flag
實(shí)例_write方法的執(zhí)行流程
此方法用于真正寫入文件
- 查看實(shí)例的fd屬性是否存在(文件是否打開成功)
- 成功,調(diào)用fs模塊的write方法正式寫入數(shù)據(jù)
- 更新實(shí)例對象下的len以及pos屬性
- 調(diào)用clearBuffer方法將緩沖區(qū)的內(nèi)容寫入
- 調(diào)用write方法傳入的回調(diào)函數(shù)cb
- 失敗,訂閱一個(gè)open事件(open事件將會(huì)在open方法中被發(fā)射),在訂閱中的回調(diào)方法中再次以相同的參數(shù)調(diào)用_write方法
- 成功,調(diào)用fs模塊的write方法正式寫入數(shù)據(jù)
實(shí)例clearBuffer方法
- 從緩沖區(qū)中取出一個(gè)數(shù)據(jù)
- 如果數(shù)據(jù)存在,調(diào)用_write方法
- 如果數(shù)據(jù)不存在,將isWriting更改為false,發(fā)射drain事件
實(shí)現(xiàn)源碼以及測試文件
let fs = require('fs'); let EventEmitter = require('events');class WriteStream extends EventEmitter {constructor(path, options) {super();let self = this;Object.assign(self, options); //還需設(shè)置默認(rèn)值self.path = path;self.isWriting = false;self.Buffer = []; //源碼中為鏈表實(shí)現(xiàn)的緩沖區(qū)self.len = null;self.pos = self.start; //初始化寫入位置self.fd = null;self.open();}open() {let self = this;fs.open(self.path, self.flags, self.mode, (err, fd) => {self.fd = fd;if (err) return self.destroy(err);self.emit('open');});}destroy(err) {fs.close(this.fd, () => {this.emit('error', err);});}write(chunk, encoding, cb) {let self = this, ret = null;encoding = encoding?encoding:self.encoding; //優(yōu)先使用write傳入的編碼方式chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);self.len += chunk.length;ret = self.highWaterMark > self.len; //判斷當(dāng)前最新的緩沖區(qū)是否已達(dá)到最高水位線if (self.isWriting) { //說明正在調(diào)用底層方法真正寫入文件,先寫入Bufferself.Buffer.push({chunk, cb});} else {self.isWriting = true;self._write(chunk, cb, () => self.clearBuffer());}return ret;}_write(chunk, cb, clear) {let self = this;if (!self.fd) return self.once('open', () => {self._write(chunk, cb, clear)});fs.write(self.fd, chunk, 0, chunk.length, self.pos, (err, bytesWritten) => {if (err) {if (self.autoClose) {self.destroy();self.emit('error', err);}}self.len -= bytesWritten;self.pos += bytesWritten;cb && cb();clear && clear();});}clearBuffer() {let self = this, data = null;data = self.Buffer.shift();if (data) {self._write(data.chunk, data.cb, () => self.clearBuffer());} else { //此時(shí)說明緩沖區(qū)已無數(shù)據(jù)self.isWriting = false;self.emit('drain');}} }module.exports = WriteStream; 復(fù)制代碼測試文件:
let WriteStream = require('./practice'); let ws = new WriteStream('./1.txt',{flags:'w',mode:0o666,start:0,encoding:'utf8',autoClose:true //當(dāng)流寫完之后自動(dòng)關(guān)閉文件,highWaterMark:3 }); let n = 9; ws.on('error',(err)=>{console.log(err) }) function write(){let flag = true;while(flag&&n>0){flag = ws.write(n+"",'utf8',()=>{console.log('ok');});n--;console.log('flag=',flag)}ws.once('drain',()=>{console.log('drain');write();}) } // ws.on('drain',()=>{ // console.log('drain'); // write(); // }) write();復(fù)制代碼參考資料: nodejs.org/dist/latest…
總結(jié)
以上是生活随笔為你收集整理的简明writeStream实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Swagger生成的接口需要权限验证的处
- 下一篇: 聊聊tomcat jdbc pool的默