#Stream流有以下四種型別:
- Readable - 可讀操作
- Writable - 可寫操作
- Duplex - 可讀可寫操作
- Transform - 操作被寫入資料,然後讀出結果
可讀流(Readable stream)
可讀流(Readable stream)介面是對你正在讀取的資料的來源的抽象。換句話說,資料來來自可讀流(Readable stream)不會分發資料,直到你表明準備就緒。 可讀流(Readable stream) 有2種模式: 流動模式(flowing mode) 和 暫停模式(paused mode). 流動模式(flowing mode)時,儘快的從底層系統讀取資料並提供給你的程式。 暫停模式(paused mode)時, 你必須明確的呼叫 stream.read() 來讀取資料。 暫停模式(paused mode) 是預設模式。 可以通過下面幾個方法,將流切換到流動模式(flowing mode)。
let fs = require('fs');
/**
* 所有初始工作模式為 paused 的 Readable 流,可以通過下面三種途徑切換到 flowing 模式:
監聽 'data' 事件
呼叫 stream.resume() 方法
呼叫 stream.pipe() 方法將資料傳送到 Writable
*/
let rs = fs.createReadStream('./1.txt',{
highWaterMark:3
});
/*
269
stream.emit('data', chunk);
stream.read(0);
rs.on('data',function (data) {
console.log(data);
});
rs.on('end',function () {
console.log('end');
});*/
//當你監聽 readable事件的時候,會進入暫停模式
//當監聽readable事件的時候,可讀流會馬上去向底層讀取檔案,然後把讀到檔案的檔案放在快取區裡const state = this._readableState;
//self.read(0); 只填充快取,但是並不會發射data事件,但是會發射stream.emit('readable');事件
//this._read(state.highWaterMark); 每次呼叫底層的方法讀取的時候是讀取3個位元組
rs.on('readable',function(){
//length就是指得快取區資料的大小
// state.length += chunk.length;==3
console.log(rs._readableState.length);
//read如果不加參數列示讀取整個快取區資料
//讀取一個欄位,如果可讀流發現你要讀的位元組小於等於快取位元組大小,則直接返回
let ch = rs.read(1);
console.log(ch);
console.log(rs._readableState.length);
/* ch = rs.read(1);
console.log(ch);
console.log(rs._readableState.length);*/
//當你讀完指定的位元組後,如果可讀流發現剩下的位元組已經比最高水位線小了。則會立馬再次讀取填滿 最高水位線
setTimeout(function(){
console.log(rs._readableState.length);
},200)
});
複製程式碼
#可寫流(Writable stream )
這個方法向底層系統寫入資料,並在資料處理完畢後呼叫所給的回撥。返回值表示你是否應該繼續立即寫入。如果資料要快取在內部,將會返回false。否則返回 true。返回值僅供參考。即使返回 false,你也可能繼續寫。但是寫會快取在記憶體裡,所以不要做的太過分。最好的辦法是等待drain 事件後,再寫入資料。
let fs = require('fs');
let ws = fs.createWriteStream('2.txt',{
flags:'w',
mode:0o666,
start:0,
highWaterMark:3
});
let count = 9;
function write(){
let flag = true;//快取區未滿
//寫入方法是同步的,但是寫入檔案的過程 非同步的。在真正寫入檔案後還會執行我們的回撥函式
while(flag && count>0){
console.log('before',count);
flag = ws.write((count)+'','utf8',(function (i) {
return ()=>console.log('after',i);
})(count));
count--;
}
}
write();//987
//監聽快取區清空事件
ws.on('drain',function () {
console.log('drain');
write();//654 321
});
ws.on('error',function (err) {
console.log(err);
});
//如果已經不再需要寫入了,可以呼叫end方法關閉寫入流,一旦呼叫end方法之後則不能再寫入
ws.end();
//write after end
//
ws.write('x');
複製程式碼
#雙工流(Duplex streams) 雙工流(Duplex streams)是同時實現了 Readable and Writable 介面。用法詳見下文
let {Duplex} = require('stream');
let index = 0;
let s = Duplex({
read(){
if(index++<3)
this.push('a');
else
this.push(null);
},
write(chunk,encoding,cb){
console.log(chunk.toString().toUpperCase());
cb();
}
});
//process.stdin 標準輸入流
//proces.stdout標準輸出流
process.stdin.pipe(s).pipe(process.stdout);
複製程式碼
#轉換流(Transform streams) 它的輸出是從輸入計算得來。 它實現了Readable 和 Writable 介面. 用法詳見下文.
let {Transform} = require('stream');
//轉換流是實現資料轉換的
let t = Transform({
transform(chunk,encoding,cb){
this.push(chunk.toString().toUpperCase());
cb();
}
});
process.stdin.pipe(t).pipe(process.stdout);
複製程式碼
let {Transform} = require('stream');
let fs = require('fs');
let rs = fs.createReadStream('./user.json');
//普通流裡的放的是Buffer,物件流裡放的物件
let toJSON = Transform({
readableObjectMode:true,//就可以向可讀流裡放物件
transform(chunk,encoding,cb){
//向可讀流裡的快取區裡放
this.push(JSON.parse(chunk.toString()));
}
});
let outJSON = Transform({
writableObjectMode:true,//就可以向可讀流裡放物件
transform(chunk,encoding,cb){
console.log(chunk);
cb();
}
});
rs.pipe(toJSON).pipe(outJSON);
複製程式碼