您好,登錄后才能下訂單哦!
本篇內容主要講解“Nodejs中可寫流write的實現方法”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Nodejs中可寫流write的實現方法”吧!
首次讀取的數據會真實寫入目標文件
其余次讀取的數據要根據讀取數據是否超出highWaterMark ,是的話存入緩存區等待寫入目標文件中
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 還有一個boolea的返回值 ws.write("1"); //flag 表示 當前要寫的值是直接是否直接寫入文件,不能超出了單次最大寫入值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,沒有調用 end 是不會調用 觸發close的,看到這里的小伙伴可以嘗試注釋end() 看看close的console是否有打印
效果
const EventEmitter = require("events"); const fs = require("fs"); class WriteStream extends EventEmitter {} module.exports = WriteStream;
鏈表&隊列的實現
https://juejin.cn/post/6973847774752145445
// 用鏈表 生成隊列 對 文件緩存區的讀取 進行優化 const Queue = require("./queue");
constructor(path, options = {}) { super(); this.path = path; this.flags = options.flags || "w"; this.encoding = options.encoding || "utf8"; this.mode = options.mode || 0o666; //默認8進制 ,6 6 6 三組分別的權限是 可讀可寫 this.autoClose = options.start || 0; this.highWaterMark = options.highWaterMark || 16 * 1024; //默認一次讀取16個字節的數據 this.len = 0; //用于維持有多少數據還沒有被寫入文件中 //是否根據等待當前讀取的最大文數據 排空后再寫入 this.needDrain = false; // // 緩存隊列 用于存放 非第一次的文件讀取 到的數據,因為第一次讀取 直接塞入目標文件中 // 除第一次 的文件讀取數據的都存放再緩存中 // this.cache = []; // 隊列做緩存 this.cache = new Queue(); // 標記是否是第一次寫入目標文件的標識 this.writing = false; this.start = options.start || 0; this.offset = this.start; //偏移量 this.open(); }
this.mode 文件操作權限 默認0o666(0o表示8進制)
3個6所占位置分別對應:文件所屬用戶對它的權限 ;文件所屬用戶組用戶對它的權限;表示其他用戶對它的權限
權限由:r--可讀(對應數值4),w--可寫(對應數值2),x--可執行(對應數值1,例如文件夾下有 .exe 這樣的標識 說明點擊可以直接執行)組成
所以默認情況下3組用戶對文件的操作權限都是可讀可寫
調用fs.open()
回調emit實例open方法,fs.open的返回值fd做參數傳入
open() { fs.open(this.path, this.flags, this.mode, (err, fd) => { this.fd = fd; this.emit("open", fd); }); }
轉化實例傳入的需要寫入的文件數據格式為buffer
判斷寫入數據長度是否大于highWaterMark,如果達到預期后,文件讀取到的數據存放再緩存里 不直接寫入目標文件(這里要排除是否是第一次讀取文件)
執行實例write 傳入的cb 并調用clearBuffer 清空緩存
判斷 是否是第一次讀取,第一次讀取 直接寫入調用 _write(待實現)
緩存隊列尾部offer 當前讀取到的數據等待寫入目標文件
write(chunk, encoding = this.encoding, cb = () => {}) { // 將數據全部轉換成buffer chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); this.len += chunk.length; // console.log({chunk},this.len ) let returnValue = this.len < this.highWaterMark; //當數據寫入后,需要在手動的將this.len-- this.needDrain = !returnValue; //如果達到預期 后 的文件讀取 到數據存放再緩存里 不直接寫入目標文件 //清空緩存 對用戶傳入的回調 進行二次包裝 let userCb = cb; cb = () => { userCb(); //清空buffer this.clearBuffer();//馬上實現 }; //此時需要判斷 是否是第一次讀取,第一次讀取 直接寫入調用 _write if (!this.writing) { // 第一次||緩存隊列已清空完畢 this.writing = true; // console.log("first write"); this._write(chunk, encoding, cb);//馬上實現 } else { //緩存隊列尾部offer 當前讀取到的數據等待寫入目標文件 this.cache.offer({ chunk, encoding, cb, }); } return returnValue; }
隊列執行順序,先進先出原則
this.cache.poll() 依次拿取頭部數據執行this._write寫入目標文件
緩存隊列poll出來的data如果不存在,則說明是第一次寫入的行為||緩存隊列已清空。this.writing = false; 下次的文件讀取可以直接寫入目標文件
如果this.needDrain又達到預期,文件讀取到數據存放再緩存里 不直接寫入目標文件
clearBuffer() { //寫入成功后 調用 clearBuffer--》寫入緩存第一個,第一個完成后,再繼續 第二個 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) { // 如果是緩存,觸發drain this.emit("drain"); } } }
fs.open()是異步的,成功讀取后fd會是一個number類型
根據fd的type 決定是否訂閱一次open,并回調自己(直到fd類型為number)
fd類型為number:調用fs.write,寫入當前的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; //維護偏移量 this.len -= written; //把緩存的個數減少 cb(); //寫入成功 // console.log(this.cache); }); }
const WriteStream = require("./initWriteStream"); let ws = new WriteStream(bPath, { highWaterMark: 3, }); let i = 0; function write() { //寫入0-9個 let flag = true; while (i < 10 && flag) { flag = ws.write(i++ + ""); console.log(flag); } } ws.on("drain", function () { // 只有當我們寫入的數據達到預期,并且數據被清空后才會觸發drain ?? console.log("寫完了"); write(); }); write();
10個數字,依次寫入,3次達到最大預期值,然后依次清空了3次緩存結果符合預期
目標文件中查看是否正確寫入了我們預期的數值
到此,相信大家對“Nodejs中可寫流write的實現方法”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。