一,為什么需要流芯砸?
????????當我們學習一個東西的時候萧芙,首先我們要知道為什么要學習?那我們?yōu)槭裁匆褂昧髂匾亦郑吭趎ode中讀取文件的方式有來兩種末购,一個是利用fs模塊,一個是利用流來讀取虎谢。如果讀取小文件盟榴,我們可以使用fs讀取,fs讀取文件的時候婴噩,是將文件一次性讀取到本地內存擎场。而如果讀取一個大文件,一次性讀取會占用大量內存几莽,效率很低迅办,這個時候需要用流來讀取。流是將數(shù)據(jù)分割段章蚣,一段一段的讀取站欺,效率很高。
二,流的概念
流是一種抽象的接口矾策,node中很多對象都對它進行了實現(xiàn)磷账。
所有流的對象都是EventEmitter的實例,都實現(xiàn)了EventEmitter的接口贾虽。
也就是流具有事件的能力逃糟,可以通過發(fā)射事件來反饋流的狀態(tài)。這樣我們就可以注冊監(jiān)聽流的事件蓬豁,來達到我們的目的绰咽。也就是我們訂閱了流的事件,這個事件觸發(fā)時地粪,流會通知我取募,然后我就可以做相應的操作了。
三驶忌,流的分類
????????Readable Stream :可讀數(shù)據(jù)流
????????Writeable Stream :可寫數(shù)據(jù)流
????????Duplex Stream :雙向數(shù)據(jù)流矛辕,可以同時讀和寫
????????Transform Stream: 轉換數(shù)據(jù)流,可讀可寫付魔,同時可以轉換(處理)數(shù)據(jù)
四,可讀流介紹
可讀流的兩種模式
可讀流有兩種模式:flowing和paused
1)在流動模式下飞蹂,可讀流自動從系統(tǒng)底層讀取數(shù)據(jù)几苍,并通過EventEmitter接口的事件盡快
將數(shù)據(jù)提供給應用。
2)在暫停模式下陈哑,必須顯示調用stream.read()方法來從流中讀取數(shù)據(jù)片段妻坝。
注意:如果可讀流切換到流動模式,并且沒有消費者處理流中的數(shù)據(jù)惊窖,這些數(shù)據(jù)將會丟失刽宪。
下面介紹Readable流有以下幾種事件:
? 1. 'Readable'事件
? 2. 'data'事件 - 數(shù)據(jù)正在傳遞時,觸發(fā)該事件(以chunk數(shù)據(jù)塊為對象)
? 3. 'end'事件 - 數(shù)據(jù)傳遞完成后界酒,會觸發(fā)該事件圣拄。
? 4. 'close'事件
? 5. 'error'事件
?所有這些事件都可以在官方API文檔中找到例子。我們可以監(jiān)聽流的這些事件毁欣,來完成相應操作庇谆。
我們來寫個小例子:
```
let fs = require('fs');
let ReadStream = require('./ReadStream');
let rs = ReadStream('./1.txt', {
? ? flags: 'r',
? ? encoding: 'utf8',
? ? start: 3,
? ? end: 7,
? ? highWaterMark: 3
});
rs.on('open', function () {
? ? console.log("open");
});
rs.on('data', function (data) {
? ? console.log(data);
});
rs.on('end', function () {
? ? console.log("end");
});
rs.on('close', function () {
? ? console.log("close");
});
/**
open
456
789
end
close
**/
```
五,可寫流介紹
常用的方法:
1凭疮,Writable流的write(chunk[,encoding] [,callback])方法可以把數(shù)據(jù)寫入流中饭耳。
其中,chunk是待寫入的數(shù)據(jù)执解,是Buffer或String對象寞肖。這個參數(shù)是必須的,其它參數(shù)都是可選的。如果chunk是String對象新蟆,encoding可以用來指定字符串的編碼格式觅赊,write會根據(jù)編碼格式將chunk解碼成字節(jié)流再來寫入。callback是數(shù)據(jù)完全刷新到流中時會執(zhí)行的回調函數(shù)栅葡。write方法返回布爾值茉兰,當數(shù)據(jù)被完全處理后返回true(不一定是完全寫入設備哦)。
2欣簇,Writable流的end([chunk] [,encoding] [,callback])方法可以用來結束一個可寫流规脸。它的三個參數(shù)都是可選的。chunk和encoding的含義與write方法類似熊咽。callback是一個可選的回調莫鸭,當你提供它時,它會被關聯(lián)到Writable的finish事件上横殴,這樣當finish事件發(fā)射時它就會被調用被因。
常用的事件:
drain事件:當一個流不處在 drain 的狀態(tài), 對 write() 的調用會緩存數(shù)據(jù)塊衫仑, 并且返回 false梨与。 一旦所有當前所有緩存的數(shù)據(jù)塊都排空了(被操作系統(tǒng)接受來進行輸出), 那么 'drain' 事件就會被觸發(fā)
finish事件:在調用了 stream.end() 方法文狱,且緩沖區(qū)數(shù)據(jù)都已經(jīng)傳給底層系統(tǒng)之后粥鞋, 'finish' 事件將被觸發(fā)。
我們來寫個小例子:
let fs = require('fs');
let FileWriteStream = require('./FileWriteStream');
let ws = FileWriteStream('./2.txt',{
? ? flags:'w',
? ? encoding:'utf8',
? ? highWaterMark:3
});
let i = 10;
function write(){
? ? let? flag = true;
? ? while(i&&flag){
? ? ? ? flag = ws.write("1",'utf8',(function(i){
? ? ? ? ? ? return function(){
? ? ? ? ? ? ? ? console.log(i);
? ? ? ? ? ? }
? ? ? ? })(i));
? ? ? ? i--;
? ? ? ? console.log(flag);
? ? }
}
write();
ws.on('drain',()=>{
? ? console.log("drain");
? ? write();
});
六瞄崇,緩存區(qū)
不管是可讀流還是可寫流都會將數(shù)據(jù)存儲到內部的緩沖器中呻粹。
緩沖器的大小取決于傳遞給流構造函數(shù)的highWaterMark選項。對于普通的流苏研,highWaterMark
指定了總共的字節(jié)數(shù)等浊。對于工作在對象模式的流,指定了對象的總數(shù)摹蘑。