node 流学习笔记 - 可写流
生活随笔
收集整理的這篇文章主要介紹了
node 流学习笔记 - 可写流
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
可寫流
- 可寫流沒有會(huì)創(chuàng)建,有內(nèi)容的話會(huì)清空
- 默認(rèn)情況下一次能寫 16 * 1024
- 緩存區(qū),第一次寫入是真的向文件里寫入,第二次在寫入的時(shí)候放入到了緩存區(qū)里
- 寫入時(shí)候返回一個(gè)boolean類型,返回為false時(shí)不要在寫入
- 當(dāng)內(nèi)存和正在寫入的內(nèi)容消耗完后會(huì)觸發(fā) drain 事件。
讀取的時(shí)候,讀到幾個(gè)就發(fā)射出幾個(gè),而可寫流默認(rèn)情況下一次能寫入 16 * 1024。舉例:讀取 30 個(gè),但是寫一次寫入3個(gè),多出來的 27個(gè)則放入到緩存區(qū)里。第一次是真往文件里寫入,后面則全部放到緩存區(qū)中,寫完后則清空緩存區(qū)。
let fs = require('fs');let ws = fs.createWriteStream('./2.text', {flags: 'w', // 模式encoding: 'utf8', // 編碼start: 0, // 從哪兒開始寫highWaterMark: 3 // 最高的水位線 16 * 1024 });// 寫入 寫入的內(nèi)容必須是字符串或者buffer // flag 表示是否還有緩存空間 當(dāng)寫入的次數(shù)大于等于 highWaterMark 則返回flase // 可讀流配合可寫流使用。flag 為了保證讀取和寫入可以節(jié)約內(nèi)存,而不是瘋狂的讀 let flag = ws.write('1', 'utf8', () => { });復(fù)制代碼舉例子:一次能寫3個(gè),9個(gè)數(shù)字,先寫入 9 8 7 然后等一等,等寫完后在繼續(xù)寫入 6 5 4 。。。。比如一個(gè)人能吃饅頭一次最多吃3個(gè),如果不停的給他饅頭,嘴里沒有吃完則將饅頭放到地上(緩存區(qū)里去)。等吃完在去拿來吃。
let fs = require('fs');let ws = fs.createWriteStream('./3.text', {flags: 'w', // 模式encoding: 'utf8', // 編碼start: 0, // 從哪兒開始寫highWaterMark: 3 // 最高的水位線 16 * 1024 });let i = 9; function write() {// 是否可寫入let flag = true;while(flag && i >= 0) {// 第一次 9 8 7 當(dāng)是 7 的時(shí)候 flag 為falseflag = ws.write(i-- + '');} } // 只有嘴里塞滿了吃完了。才會(huì)觸發(fā) // drain 觸發(fā)時(shí)機(jī),只有當(dāng)嘴(highWaterMark)滿了,才可能觸發(fā) drain // 只有當(dāng)嘴里的和地上的(內(nèi)存里)都吃完了,才會(huì)觸發(fā) drain 方法 ws.on('drain', () => {console.log('吃完了。');// 繼續(xù)吃write(); }) write(); 復(fù)制代碼可寫流原理
- 默認(rèn)屬性
- open 打開文件
- 關(guān)閉文件
- write 寫入
- _write && clearBuffer 方法實(shí)現(xiàn)
完整代碼
<!--WriteStream.js--> let fs = require('fs'); let EventEmitter = require('events');class WriteStream extends EventEmitter {constructor(path, options = {}) {super();this.path = path;this.flags = options.flags || 'w';this.encoding = options.encoding || 'utf8';this.start = options.start || 0;this.pos = this.start;this.mode = options.mode || 0o666;this.autoClose = options.autoClose || true;this.highWaterMark = options.highWaterMark || 16 * 1024;// 先打開文件 異步調(diào)用 觸發(fā) open 事件后拿到 fdthis.open();// 寫文件的時(shí)候需要的參數(shù)// 第一次寫入是真的往文件里寫入this.writing = false; // 默認(rèn)第一次沒有正在寫入// 緩存區(qū)this.cache = [];// 維護(hù)一個(gè)變量 表示緩存的長(zhǎng)度this.len = 0;// 是否觸發(fā) drain 事件this.needDrain = false;}// clearBuffer() {let buffer = this.cache.shift();if (buffer) {// 緩存里有this._write(buffer.chunk, buffer.encoding, () => this.clearBuffer());} else {// 緩存里沒有// 需要出發(fā)drain事件if (this.needDrain) {this.writing = false; // 不需要再寫入到內(nèi)存里。this.needDrain = false;this.emit('drain');}}}_write(chunk, encoding, clearBuffer) {// write 同步調(diào)用 fd 還沒獲取到,獲取到fd后在執(zhí)行writeif (typeof this.fd !== 'number') {return this.once('open', ()=>this._write(chunk, encoding, clearBuffer));}fs.write(this.fd, chunk, 0, chunk.length, this.pos, (err, byteWritten) => {this.pos += byteWritten;this.len -= byteWritten; // 每次寫入后就要在內(nèi)存中減少 相當(dāng)于把饅頭吃掉了this.clearBuffer(); // 第一次寫完});}// 客戶調(diào)用的是write方法寫入內(nèi)容write(chunk, encoding = this.encoding, callback) {// 將 chunk 變成bufferchunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);this.len += chunk.length; // 維護(hù)緩存的長(zhǎng)度let ret = this.len < this.highWaterMark;if (!ret) {this.needDrain = true; // 需要觸發(fā)drain事件}if (this.writing) {// 正在寫入應(yīng)該放到內(nèi)存中this.cache.push({chunk,encoding,callback});} else {this.writing = true;// 第一次寫入this._write(chunk, encoding, ()=>this.clearBuffer());}return ret; // 表示能不能繼續(xù)寫。false 表示下次寫的時(shí)候就要占用更多內(nèi)存}// 關(guān)閉文件destory() {if(typeof this.fd !== 'number') {// 沒有打開過this.emit('close');} else {fs.close(this.fd, () => {this.emit('close');});}}// 打開文件open() {fs.open(this.path, this.flags, this.mode, (err, fd) => {if (err) {// 是否需要關(guān)閉if(this.autoClose) {// 如果自動(dòng)關(guān)閉就銷毀文件描述符 fdthis.destory();}this.emit('error', err);return;}this.fd = fd;this.emit('open', this.fd);});}}module.exports = WriteStream;<!--應(yīng)用--> let fs = require('fs'); let WS = require('./WriteStream'); let ws = new WS('./3.text', {flags: 'w', // 文件如果不存在則創(chuàng)建,文件存在則清空highWaterMark: 3, // 設(shè)置當(dāng)前緩存區(qū)大小即嘴有多大encoding: 'utf8', // 文件里存放的是二進(jìn)制start: 0,autoClose: true, // 自動(dòng)關(guān)閉mode: 0o666 // 可讀可寫 });let i = 9;function write() {let flag = true;while(flag && i >= 0) {flag = ws.write(i-- + '', 'utf8');} } // drain 觸發(fā)時(shí)機(jī),只有當(dāng)嘴(highWaterMark)滿了,才可能觸發(fā) drain // 只有當(dāng)嘴里的和地上的(內(nèi)存里)都吃完了,才會(huì)觸發(fā) drain 方法 write(); ws.on('drain', () => {console.log('寫完了');write(); }); 復(fù)制代碼總結(jié)
以上是生活随笔為你收集整理的node 流学习笔记 - 可写流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux学习笔记6月1日任务
- 下一篇: mysql字符类型