摘要:在可讀流事件里我們就必須調(diào)用方法。當一個對象就意味著我們想發(fā)出信號這個流沒有更多數(shù)據(jù)了自定義可寫流為了實現(xiàn)可寫流,我們需要使用流模塊中的構(gòu)造函數(shù)。我們只需給構(gòu)造函數(shù)傳遞一些選項并創(chuàng)建一個對象。
前言
什么是流呢?看字面意思,我們可能會想起生活中的水流,電流。
但是流不是水也不是電,它只是描述水和電的流動;所以說流是抽象的。
在node.js中流是一個抽象接口,它不關(guān)心文件內(nèi)容,只關(guān)注是否從文件中讀到了數(shù)據(jù),以及讀到數(shù)據(jù)之后的處理,接著看:
流是一組有序的,有起點和終點的字節(jié)數(shù)據(jù)傳輸手段
它不關(guān)心文件的整體內(nèi)容,只關(guān)注是否從文件中讀到了數(shù)據(jù);以及讀到數(shù)據(jù)之后的處理
流是一個抽象接口,被node中的很多對象所實現(xiàn)。比如HTTP服務(wù)器request和response對象都是流,TCP服務(wù)器中的socket也是流。
看看官網(wǎng)的介紹:
這里說了“所有的流都是EventEmitter的實例” 所以流繼承了EventEmitter類。再來看流的類型:
2.流的類型Reacable-可讀的流(例如fs.createReadStream())
Writrable-可寫的流(例如fs.createWriteStream())
Duplex-可讀寫的流(例如net.Socket)
Transform-在讀寫的過程中可以修改和變換數(shù)據(jù)的Duplex流(例如zlib.createDuplex())
3.流的數(shù)據(jù)模式流中的數(shù)據(jù)有兩種模式,二進制模式和對象模式.
二進制模式, 每個分塊都是buffer或者string對象.
對象模式, 流內(nèi)部處理的是一系列普通對象.
注意:4.可讀流(createReadStream) 4.1 創(chuàng)建可讀流
所有使用 Node.js API 創(chuàng)建的流對象都只能操作 strings 和 Buffer對象。但是,通過一些第三方流的實現(xiàn),你依然能夠處理其它類型的 JavaScript 值 (除了 null,它在流處理中有特殊意義)。 這些流被認為是工作在 “對象模式”(object mode)。 在創(chuàng)建流的實例時,可以通過 objectMode 選項使流的實例切換到對象模式。試圖將已經(jīng)存在的流切換到對象模式是不安全的。
說了那么多,現(xiàn)在開始寫流:
這里說說流程:
首先可讀流會打開文件,觸發(fā)open事件
接著開始讀取,瘋狂的觸發(fā)data事件
然后讀完了,觸發(fā)end事件
最后因為設(shè)置了autoClose為true,自動關(guān)閉文件觸發(fā)close事件
可以看到,data事件不斷的被觸發(fā),當我們想讀一下停一下時怎么辦呢?
這里就需要聊聊可讀流的兩種模式:
可讀流事實上工作在下面兩種模式之一:flowing 和 paused
在 flowing 模式下, 可讀流自動從系統(tǒng)底層讀取數(shù)據(jù),并通過 EventEmitter 接口的事件盡快將數(shù)據(jù)提供給應(yīng)用。
在 paused 模式下,必須顯式調(diào)用 stream.read() 方法來從流中讀取數(shù)據(jù)片段。
初始工作模式為 paused 的 Readable 流,可以通過下面三種途徑切換到 flowing 模式:
1. 監(jiān)聽 "data" 事件 2. 調(diào)用 stream.resume() 方法
3.調(diào)用 stream.pipe() 方法將數(shù)據(jù)發(fā)送到 Writable
注意:
如果 Readable 切換到 flowing 模式,且沒有消費者處理流中的數(shù)據(jù),這些數(shù)據(jù)將會丟失。 比如, 調(diào)用了 readable.resume() 方法卻沒有監(jiān)聽 "data" 事件,或是取消了 "data" 事件監(jiān)聽,就有可能出現(xiàn)這種情況
在 paused 模式下,必須顯式調(diào)用 stream.read() 方法來從流中讀取數(shù)據(jù)片段。
在可讀流"readable"事件里我們就必須調(diào)用stream.read()方法。
這里需要明白三點:
先創(chuàng)建一個1.txt
1.當我只要創(chuàng)建一個流 就會先把緩存區(qū) 填滿,等待著你自己消費
2.當你消費小于 最高水位線時 會自動添加highWaterMark這么多數(shù)據(jù)
3.如果當前緩存區(qū)被清空后會再次觸發(fā)readable事件
用Readable創(chuàng)建對象readable后,便得到了一個可讀流。
如果實現(xiàn)_read方法,就將流連接到一個底層數(shù)據(jù)源。
流通過調(diào)用_read向底層請求數(shù)據(jù),底層再調(diào)用流的push方法將需要的數(shù)據(jù)傳遞過來。
當readable連接了數(shù)據(jù)源后,下游便可以調(diào)用readable.read(n)向流請求數(shù)據(jù),同時監(jiān)聽readable的data事件來接收取到的數(shù)據(jù)。
5.可寫流(createWriteStream) 5.1 創(chuàng)建可寫流 5.1.1 write方法 5.1.2 end方法表明接下來沒有數(shù)據(jù)要被寫入 Writable 通過傳入可選的 chunk 和 encoding 參數(shù),可以在關(guān)閉流之前再寫入一段數(shù)據(jù) 如果傳入了可選的 callback 函數(shù),它將作為 "finish" 事件的回調(diào)函數(shù)5.1.3 drain方法
drain事件的觸發(fā)條件,必須滿足兩個條件:
1.當前緩存區(qū)滿了,不能再寫了
2.緩存區(qū)滿了后被清空了,才會觸發(fā)drain事件
我們在開發(fā)中可能會遇到,要把可讀流讀出的數(shù)據(jù)需要放到可寫流中去寫入到文件里面,這時就可以用pipe方法
6.1 pipe的原理pipe方法的原理很簡單,就是讀一點,寫一點,上代碼
let fs = require("fs"); let ws = fs.createWriteStream("./2.txt"); let rs = fs.createReadStream("./1.txt"); rs.on("data", data => { var flag = ws.write(data); if(!flag) rs.pause(); }); ws.on("drain", () => { rs.resume(); }); rs.on("end", () => { ws.end(); });6.2 pipe的用法
let from = fs.createReadStream("./1.txt"); let to = fs.createWriteStream("./2.txt"); from.pipe(to);6.3 unpipe方法
readable.unpipe()方法將之前通過stream.pipe()方法綁定的流分離
let fs = require("fs"); let from = fs.createReadStream("./1.txt"); let to = fs.createWriteStream("./2.txt"); from.pipe(to); setTimeout(() => { console.log("關(guān)閉向2.txt的寫入"); from.unpipe(writable); console.log("手動關(guān)閉可寫流"); to.end(); }, 1000);7.自定義流
我們可以引入stream模塊,想實現(xiàn)什么流 就繼承這個流。
7.1 自定義可讀流我們可以直接把供使用的數(shù)據(jù)push出去。
當push一個null對象就意味著我們想發(fā)出信號——這個流沒有更多數(shù)據(jù)了
7.2 自定義可寫流為了實現(xiàn)可寫流,我們需要使用流模塊中的Writable構(gòu)造函數(shù)。 我們只需給Writable構(gòu)造函數(shù)傳遞一些選項并創(chuàng)建一個對象。唯一需要的選項是write函數(shù),該函數(shù)揭露數(shù)據(jù)塊要往哪里寫。
有了雙工流,我們可以在同一個對象上同時實現(xiàn)可讀和可寫,就好像同時繼承這兩個接口。 重要的是雙工流的可讀性和可寫性操作完全獨立于彼此。
net中的Socket就是一個duplex雙工流
說到這里,我想大家應(yīng)該大致了解了node.js里面的流。
之前說過在node里流還是很重要的,http里的request和response都是流。
在下一篇文章我會寫一個readStream和writeStream的簡單實現(xiàn)。
本人水平有限,有錯誤的地方希望指出。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93907.html
摘要:事件的觸發(fā)頻次同樣是由實現(xiàn)者決定,譬如在進行文件讀取時,可能每行都會觸發(fā)一次而在請求處理時,可能數(shù)的數(shù)據(jù)才會觸發(fā)一次。如果有參數(shù)傳入,它會讓可讀流停止流向某個特定的目的地,否則,它會移除所有目的地。 showImg(https://segmentfault.com/img/remote/1460000016328758?w=1967&h=821); 本文節(jié)選自 Node.js Chea...
摘要:回調(diào)函數(shù)中檢測該次寫入是否被緩沖,若是,觸發(fā)事件。若目標可寫流表示該寫入操作需要進行緩沖,則立刻將源可讀流切換至暫停模式。監(jiān)聽源可讀流的事件,相應(yīng)地結(jié)束目標可寫流。 在Node.js中,流(Stream)是其眾多原生對象的基類,它對處理潛在的大文件提供了支持,也抽象了一些場景下的數(shù)據(jù)處理和傳遞。在它對外暴露的接口中,最為神奇的,莫過于導(dǎo)流(pipe)方法了。鑒于近期自己正在閱讀Node...
摘要:中的流十分強大,它對處理潛在的大文件提供了支持,也抽象了一些場景下的數(shù)據(jù)處理和傳遞。本文將會提供兩個在編寫基于流的工具時,私以為有些用的兩個。 Node.js中的流十分強大,它對處理潛在的大文件提供了支持,也抽象了一些場景下的數(shù)據(jù)處理和傳遞。正因為它如此好用,所以在實戰(zhàn)中我們常?;谒鼇砭帉懸恍┕ぞ?函數(shù)/庫 ,但往往又由于自己對流的某些特性的疏忽,導(dǎo)致寫出的 函數(shù)/庫 在一些情況會達...
摘要:中各種用于讀取數(shù)據(jù)的對象對象描述用于讀取文件代表客戶端請求或服務(wù)器端響應(yīng)代表一個端口對象用于創(chuàng)建子進程的標準輸出流。如果子進程和父進程共享輸入輸出流,則子進程的標準輸出流被廢棄用于創(chuàng)建子進程的標準錯誤輸出流。 9. stream流 fs模塊中集中文件讀寫方法的區(qū)別 用途 使用異步方式 使用同步方式 將文件完整讀入緩存區(qū) readFile readFileSync 將文件部...
摘要:方法也可以接收一個參數(shù)表示數(shù)據(jù)請求著請求的數(shù)據(jù)大小,但是可讀流可以根據(jù)需要忽略這個參數(shù)。讀取數(shù)據(jù)大部分情況下我們只要簡單的使用方法將可讀流的數(shù)據(jù)重定向到另外形式的流,但是在某些情況下也許直接從可讀流中讀取數(shù)據(jù)更有用。 介紹本文介紹了使用 node.js streams 開發(fā)程序的基本方法。 We should have some ways of connecting programs ...
閱讀 1628·2021-11-22 13:53
閱讀 2868·2021-11-15 18:10
閱讀 2768·2021-09-23 11:21
閱讀 2515·2019-08-30 15:55
閱讀 486·2019-08-30 13:02
閱讀 765·2019-08-29 17:22
閱讀 1709·2019-08-29 13:56
閱讀 3462·2019-08-29 11:31