站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

淺談Nodejs中的可寫流write與實(shí)現(xiàn)方法

本篇文章帶大家了解一下Nodejs中的可寫流write,介紹一下Node可寫流write的實(shí)現(xiàn)。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有所幫助。

淺談Nodejs中的可寫流write與實(shí)現(xiàn)方法

【推薦學(xué)習(xí):《nodejs 教程》】

可寫流-Writable

fs.createWriteStream調(diào)用例子

  • 首次讀取的數(shù)據(jù)會(huì)真實(shí)寫入目標(biāo)文件
  • 其余次讀取的數(shù)據(jù)要根據(jù)讀取數(shù)據(jù)是否超出highWaterMark ,是的話存入緩存區(qū)等待寫入目標(biāo)文件中
const fs = require("fs"); const path = require("path"); const bPath = path.join(__dirname, "b.txt"); let ws = fs.createWriteStream(bPath, {   flags: "w",   encoding: "utf-8",   autoClose: true,   start: 0,   highWaterMark: 3, }); ws.on("open", function (fd) {   console.log("open", fd); }); ws.on("close", function () {   console.log("close"); });  //string 或者buffer,ws.write 還有一個(gè)boolea的返回值 ws.write("1"); //flag 表示 當(dāng)前要寫的值是直接是否直接寫入文件,不能超出了單次最大寫入值highWaterMark let flag = ws.write("1"); console.log({ flag });//true flag = ws.write("1"); console.log({ flag });//false flag = ws.write("1"); console.log({ flag });//false flag = ws.write("14444444"); console.log({ flag });//false ws.end(); //write+close,沒(méi)有調(diào)用 end 是不會(huì)調(diào)用 觸發(fā)close的,看到這里的小伙伴可以嘗試注釋end() 看看close的console是否有打印
  • 效果

淺談Nodejs中的可寫流write與實(shí)現(xiàn)方法

自定義可寫流initWriteStream

繼承EventEmitter發(fā)布訂閱

const EventEmitter = require("events"); const fs = require("fs"); class WriteStream extends EventEmitter {} module.exports = WriteStream;

鏈表生成隊(duì)列做文件讀取的緩存

鏈表&隊(duì)列的實(shí)現(xiàn)

https://juejin.cn/post/6973847774752145445

// 用鏈表 生成隊(duì)列 對(duì) 文件緩存區(qū)的讀取 進(jìn)行優(yōu)化 const Queue = require("./queue");

初始化實(shí)例默認(rèn)數(shù)據(jù)constructor()

 constructor(path, options = {}) {     super();     this.path = path;     this.flags = options.flags || "w";     this.encoding = options.encoding || "utf8";     this.mode = options.mode || 0o666; //默認(rèn)8進(jìn)制 ,6 6 6  三組分別的權(quán)限是 可讀可寫     this.autoClose = options.start || 0;     this.highWaterMark = options.highWaterMark || 16 * 1024; //默認(rèn)一次讀取16個(gè)字節(jié)的數(shù)據(jù)     this.len = 0; //用于維持有多少數(shù)據(jù)還沒(méi)有被寫入文件中     //是否根據(jù)等待當(dāng)前讀取的最大文數(shù)據(jù) 排空后再寫入     this.needDrain = false; //     // 緩存隊(duì)列 用于存放 非第一次的文件讀取 到的數(shù)據(jù),因?yàn)榈谝淮巫x取 直接塞入目標(biāo)文件中     // 除第一次 的文件讀取數(shù)據(jù)的都存放再緩存中     // this.cache = [];     // 隊(duì)列做緩存     this.cache = new Queue();     // 標(biāo)記是否是第一次寫入目標(biāo)文件的標(biāo)識(shí)     this.writing = false;     this.start = options.start || 0;     this.offset = this.start; //偏移量     this.open();   }
  • this.mode 文件操作權(quán)限 默認(rèn)0o666(0o表示8進(jìn)制)

    • 3個(gè)6所占位置分別對(duì)應(yīng):文件所屬用戶對(duì)它的權(quán)限 ;文件所屬用戶組用戶對(duì)它的權(quán)限;表示其他用戶對(duì)它的權(quán)限

    • 權(quán)限由:r–可讀(對(duì)應(yīng)數(shù)值4),w–可寫(對(duì)應(yīng)數(shù)值2),x–可執(zhí)行(對(duì)應(yīng)數(shù)值1,例如文件夾下有 .exe 這樣的標(biāo)識(shí) 說(shuō)明點(diǎn)擊可以直接執(zhí)行)組成

    • 所以默認(rèn)情況下3組用戶對(duì)文件的操作權(quán)限都是可讀可寫

open()

  • 調(diào)用fs.open()
  • 回調(diào)emit實(shí)例open方法,fs.open的返回值fd做參數(shù)傳入
 open() {     fs.open(this.path, this.flags, this.mode, (err, fd) => {       this.fd = fd;       this.emit("open", fd);     });   }

write()

  • 轉(zhuǎn)化實(shí)例傳入的需要寫入的文件數(shù)據(jù)格式為buffer
  • 判斷寫入數(shù)據(jù)長(zhǎng)度是否大于highWaterMark,如果達(dá)到預(yù)期后,文件讀取到的數(shù)據(jù)存放再緩存里 不直接寫入目標(biāo)文件(這里要排除是否是第一次讀取文件)
  • 執(zhí)行實(shí)例write 傳入的cb 并調(diào)用clearBuffer 清空緩存
  • 判斷 是否是第一次讀取,第一次讀取 直接寫入調(diào)用 _write(待實(shí)現(xiàn))
  • 緩存隊(duì)列尾部offer 當(dāng)前讀取到的數(shù)據(jù)等待寫入目標(biāo)文件
 write(chunk, encoding = this.encoding, cb = () => {}) {     //  將數(shù)據(jù)全部轉(zhuǎn)換成buffer     chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);      this.len += chunk.length;     // console.log({chunk},this.len )     let returnValue = this.len < this.highWaterMark;     //當(dāng)數(shù)據(jù)寫入后,需要在手動(dòng)的將this.len--     this.needDrain = !returnValue; //如果達(dá)到預(yù)期 后 的文件讀取 到數(shù)據(jù)存放再緩存里 不直接寫入目標(biāo)文件     //清空緩存 對(duì)用戶傳入的回調(diào) 進(jìn)行二次包裝     let userCb = cb;     cb = () => {       userCb();       //清空buffer       this.clearBuffer();//馬上實(shí)現(xiàn)     };      //此時(shí)需要判斷 是否是第一次讀取,第一次讀取 直接寫入調(diào)用 _write     if (!this.writing) {       // 第一次||緩存隊(duì)列已清空完畢       this.writing = true;       // console.log("first write");       this._write(chunk, encoding, cb);//馬上實(shí)現(xiàn)     } else {     //緩存隊(duì)列尾部offer 當(dāng)前讀取到的數(shù)據(jù)等待寫入目標(biāo)文件       this.cache.offer({         chunk,         encoding,         cb,       });     }     return returnValue;   }

clearBuffer()依次清空緩存隊(duì)列

  • 隊(duì)列執(zhí)行順序,先進(jìn)先出原則
  • this.cache.poll() 依次拿取頭部數(shù)據(jù)執(zhí)行this._write寫入目標(biāo)文件
  • 緩存隊(duì)列poll出來(lái)的data如果不存在,則說(shuō)明是第一次寫入的行為||緩存隊(duì)列已清空。this.writing = false; 下次的文件讀取可以直接寫入目標(biāo)文件
  • 如果this.needDrain又達(dá)到預(yù)期,文件讀取到數(shù)據(jù)存放再緩存里 不直接寫入目標(biāo)文件
clearBuffer() {     //寫入成功后 調(diào)用 clearBuffer--》寫入緩存第一個(gè),第一個(gè)完成后,再繼續(xù) 第二個(gè)     let data = this.cache.poll();     // console.log('this.cache',this.cache)     if (data) {       //有值 寫入文件       this._write(data.chunk, data.encoding, data.cb);     } else {       this.writing = false;       if (this.needDrain) {         // 如果是緩存,觸發(fā)drain         this.emit("drain");       }     }   }

_write()

  • fs.open()是異步的,成功讀取后fd會(huì)是一個(gè)number類型
  • 根據(jù)fd的type 決定是否訂閱一次open,并回調(diào)自己(直到fd類型為number)
  • fd類型為number:調(diào)用fs.write,寫入當(dāng)前的chunk,
 _write(chunk, encoding, cb) {     if (typeof this.fd !== "number") {       return this.once("open", () => this._write(chunk, encoding, cb));     }     fs.write(this.fd, chunk, 0, chunk.length, this.offset, (err, written) => {       this.offset += written; //維護(hù)偏移量       this.len -= written; //把緩存的個(gè)數(shù)減少       cb(); //寫入成功       // console.log(this.cache);     });   }

測(cè)試自定義的Writable

const WriteStream = require("./initWriteStream");  let ws = new WriteStream(bPath, {   highWaterMark: 3, });  let i = 0; function write() {   //寫入0-9個(gè)   let flag = true;   while (i < 10 && flag) {     flag = ws.write(i++ + "");      console.log(flag);   } } ws.on("drain", function () {   // 只有當(dāng)我們寫入的數(shù)據(jù)達(dá)到預(yù)期,并且數(shù)據(jù)被清空后才會(huì)觸發(fā)drain ⌚️   console.log("寫完了");   write(); });  write();
  • 10個(gè)數(shù)字,依次寫入,3次達(dá)到最大預(yù)期值,然后依次清空了3次緩存結(jié)果符合預(yù)期

淺談Nodejs中的可寫流write與實(shí)現(xiàn)方法

  • 目標(biāo)文件中查看是否正確寫入了我們預(yù)期的數(shù)值

淺談Nodejs中的可寫流write與實(shí)現(xiàn)方法

贊(0)
分享到: 更多 (0)
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
爽爽精品dvd蜜桃成熟时电影院| 国产精品户外野外| 人妻无码久久精品人妻| 亚洲精品欧洲精品| 亚洲动漫精品无码av天堂| 成人区人妻精品一区二区不卡视频| 日韩电影中文字幕| 亚洲性日韩精品一区二区三区| 精品国产一区二区三区av片| 亚洲精品无码中文久久字幕| 国产福利91精品一区二区| 538精品视频在线观看| 久久亚洲私人国产精品| 久久一区二区三区精品| 亚洲国产精品嫩草影院在线观看| 国产午夜精品一区二区三区嫩草 | 国产精品lululu在线观看| 亚洲精品日韩中文字幕久久久| 99国产精品自在自在久久| 日韩精品久久久久久免费| 午夜精品久久久久久久| 久久青草精品38国产| 久久99精品波多结衣一区| 久久精品午夜福利| 久久国产精品电影| 一区二区三区国产精品| 日产精品一线二线三线芒果| 日韩精品一区二区三区色欲AV | 91精品国产自产在线观看| 91精品福利视频| 真实国产乱子伦精品免费| 91精品国产自产在线观看高清| 一级香蕉精品视频在线播放| 久久香蕉超碰97国产精品| 99久久99久久精品免费观看| 久久ww精品w免费人成| 91久久精品国产免费一区 | 日韩成视频在线观看| 亚洲人午夜射精精品日韩| 久久久无码精品亚洲日韩软件| 日韩一卡2卡3卡4卡新区亚洲|