中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久

Nodejs Stream 數據流使用手冊
來源:易賢網 閱讀:951 次 日期:2016-07-08 10:49:12
溫馨提示:易賢網小編為您整理了“Nodejs Stream 數據流使用手冊”,方便廣大網友查閱!

這篇文章主要介紹了Nodejs Stream 數據流使用手冊的相關資料,感興趣的小伙伴一起學習吧

1、介紹

本文介紹了使用 node.js streams 開發程序的基本方法。

<code class="hljs mizar">"We should have some ways of connecting programs like garden hose--screw in

another segment when it becomes necessary to massage data in

another way. This is the way of IO also."

Doug McIlroy. October 11, 1964</code>

最早接觸Stream是從早期的unix開始的數十年的實踐證明Stream 思想可以很簡單的開發出一些龐大的系統。在unix里,Stream是通過 |實現的;在node中,作為內置的stream模塊,很多核心模塊和三方模塊都使用到。和unix一樣,node Stream主要的操作也是.pipe(),使用者可以使用反壓力機制來控制讀和寫的平衡。

Stream 可以為開發者提供可以重復使用統一的接口,通過抽象的Stream接口來控制Stream之間的讀寫平衡。

2、為什么使用Stream

node中的I/O是異步的,因此對磁盤和網絡的讀寫需要通過回調函數來讀取數據,下面是一個文件下載服務器的簡單代碼:

<code class="hljs javascript">var http = require('http');

var fs = require('fs');

var server = http.createServer(function (req, res) {

fs.readFile(__dirname + '/data.txt', function (err, data) {

res.end(data);

});

});

server.listen(8000);</code>

這些代碼可以實現需要的功能,但是服務在發送文件數據之前需要緩存整個文件數據到內存,如果"data.txt"文件很大且并發量很大的話,會浪費很多內存。因為用戶需要等到整個文件緩存到內存才能接受的文件數據,這樣導致用戶體驗相當不好。不過還好(req, res)兩個參數都是Stream,這樣我們可以用fs.createReadStream()代替fs.readFile():

<code class="hljs javascript">var http = require('http');

var fs = require('fs');

var server = http.createServer(function (req, res) {

var stream = fs.createReadStream(__dirname + '/data.txt');

stream.pipe(res);

});

server.listen(8000);</code>

.pipe()方法監聽fs.createReadStream()的'data' 和'end'事件,這樣"data.txt"文件就不需要緩存整個文件,當客戶端連接完成之后馬上可以發送一個數據塊到客戶端。使用.pipe()另一個好處是可以解決當客戶端延遲非常大時導致的讀寫不平衡問題。如果想壓縮文件再發送,可以使用三方模塊實現:

<code class="hljs javascript">var http = require('http');

var fs = require('fs');

var oppressor = require('oppressor');

var server = http.createServer(function (req, res) {

var stream = fs.createReadStream(__dirname + '/data.txt');

stream.pipe(oppressor(req)).pipe(res);

});

server.listen(8000);</code>

這樣文件就會對支持gzip和deflate的瀏覽器進行壓縮。oppressor 模塊會處理所有的content-encoding。

Stream使開發程序變得簡單。

3、基礎概念

有五種基本的Stream: readable, writable, transform, duplex, and”classic”.

3-1、pipe

所有類型的Stream收是使用 .pipe() 來創建一個輸入輸出對,接收一個可讀流src并將其數據輸出到可寫流dst,如下:

<code class="hljs perl">src.pipe(dst)</code>

.pipe( dst )方法為返回dst流,這樣就可以接連使用多個.pipe(),如下:

<code class="hljs perl">a.pipe( b ).pipe( c ).pipe( d )</code>

功能與下面的代碼相同:

<code class="hljs perl">a.pipe( b );

b.pipe( c );

c.pipe( d );</code>

3-2、readable streams

通過調用Readable streams的 .pipe()方法可以把Readable streams的數據寫入一個Writable , Transform, 或者Duplex stream。

<code class="hljs perl">readableStream.pipe( dst )</code>

1>創建 readable stream

這里我們創建一個readable stream!

<code class="hljs perl">var Readable = require('stream').Readable;

var rs = new Readable;

rs.push('beep ');

rs.push('boop\n');

rs.push(null);

rs.pipe(process.stdout);

$ node read0.js

beep boop

</code>

rs.push( null ) 通知數據接收者數據已經發送完畢.

注意到我們在將所有數據內容壓入可讀流之前并沒有調用rs.pipe(process.stdout);,但是我們壓入的所有數據內容還是完全的輸出了,這是因為可讀流在接收者沒有讀取數據之前,會緩存所有壓入的數據。但是在很多情況下, 更好的方法是只有數據接收著請求數據的時候,才壓入數據到可讀流而不是緩存整個數據。下面我們重寫 一下._read()函數:

<code class="hljs javascript">var Readable = require('stream').Readable;

var rs = Readable();

var c = 97;

rs._read = function () {

rs.push(String.fromCharCode(c++));

if (c > 'z'.charCodeAt(0)) rs.push(null);

};

rs.pipe(process.stdout);</code>

<code class="hljs bash">$ node read1.js

abcdefghijklmnopqrstuvwxyz</code>

上面的代碼通過重寫_read()方法實現了只有在數據接受者請求數據才向可讀流中壓入數據。_read()方法也可以接收一個size參數表示數據請求著請求的數據大小,但是可讀流可以根據需要忽略這個參數。

注意我們也可以用util.inherits()繼承可讀流。為了說明只有在數據接受者請求數據時_read()方法才被調用,我們在向可讀流壓入數據時做一個延時,如下:

<code class="hljs javascript">var Readable = require('stream').Readable;

var rs = Readable();

var c = 97 - 1;

rs._read = function () {

if (c >= 'z'.charCodeAt(0)) return rs.push(null);

setTimeout(function () {

rs.push(String.fromCharCode(++c));

}, 100);

};

rs.pipe(process.stdout);

process.on('exit', function () {

console.error('\n_read() called ' + (c - 97) + ' times');

});

process.stdout.on('error', process.exit);</code>

用下面的命令運行程序我們發現_read()方法只調用了5次:

<code class="hljs bash">$ node read2.js | head -c5

abcde

_read() called 5 times</code>

使用計時器的原因是系統需要時間來發送信號來通知程序關閉管道。使用process.stdout.on('error', fn) 是為了處理系統因為header命令關閉管道而發送SIGPIPE信號,因為這樣會導致process.stdout觸發EPIPE事件。如果想創建一個的可以壓入任意形式數據的可讀流,只要在創建流的時候設置參數objectMode為true即可,例如:Readable({ objectMode: true })。

2>讀取readable stream數據

大部分情況下我們只要簡單的使用pipe方法將可讀流的數據重定向到另外形式的流,但是在某些情況下也許直接從可讀流中讀取數據更有用。如下:

<code class="hljs php">process.stdin.on('readable', function () {

var buf = process.stdin.read();

console.dir(buf);

});

$ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | node consume0.js 

<buffer 0a="" 61="" 62="" 63="">

<buffer 0a="" 64="" 65="" 66="">

<buffer 0a="" 67="" 68="" 69="">

null</buffer></buffer></buffer></code>

當可讀流中有數據可讀取時,流會觸發'readable' 事件,這樣就可以調用.read()方法來讀取相關數據,當可讀流中沒有數據可讀取時,.read() 會返回null,這樣就可以結束.read() 的調用, 等待下一次'readable' 事件的觸發。下面是一個使用.read(n)從標準輸入每次讀取3個字節的例子:

<code class="hljs javascript">process.stdin.on('readable', function () {

var buf = process.stdin.read(3);

console.dir(buf);

});</code>

如下運行程序發現,輸出結果并不完全!

<code class="hljs bash">$ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | node consume1.js 

<buffer 61="" 62="" 63="">

<buffer 0a="" 64="" 65="">

<buffer 0a="" 66="" 67=""></buffer></buffer></buffer></code>

這是應為額外的數據數據留在流的內部緩沖區里了,而我們需要通知流我們要讀取更多的數據.read(0)可以達到這個目的。

<code class="hljs javascript">process.stdin.on('readable', function () {

var buf = process.stdin.read(3);

console.dir(buf);

process.stdin.read(0);

});</code>

這次運行結果如下:

<code class="hljs xml">$ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | node consume2.js 

<buffer 0a="" 64="" 65="">

<buffer 0a="" 68="" 69=""></buffer></buffer></code>

我們可以使用 .unshift() 將數據重新押回流數據隊列的頭部,這樣可以接續讀取押回的數據。如下面的代碼,會按行輸出標準輸入的內容:

<code class="hljs javascript">var offset = 0;

process.stdin.on('readable', function () {

var buf = process.stdin.read();

if (!buf) return;

for (; offset < buf.length; offset++) {

if (buf[offset] === 0x0a) {

console.dir(buf.slice(0, offset).toString());

buf = buf.slice(offset + 1);

offset = 0;

process.stdin.unshift(buf);

return;

}

}

process.stdin.unshift(buf);

});

$ tail -n +50000 /usr/share/dict/american-english | head -n10 | node lines.js 

'hearties'

'heartiest'

'heartily'

'heartiness'

'heartiness\'s'

'heartland'

'heartland\'s'

'heartlands'

'heartless'

'heartlessly'</code>

當然,有很多模塊可以實現這個功能,如:split 。

3-3、writable streams

writable streams只可以作為.pipe()函數的目的參數。如下代碼:

<code class="hljs perl">src.pipe( writableStream );</code>

1>創建 writable stream

重寫 ._write(chunk, enc, next) 方法就可以接受一個readable stream的數據。

<code class="hljs php">var Writable = require('stream').Writable;

var ws = Writable();

ws._write = function (chunk, enc, next) {

console.dir(chunk);

next();

};

process.stdin.pipe(ws);

$ (echo beep; sleep 1; echo boop) | node write0.js 

<buffer 0a="" 62="" 65="" 70="">

<buffer 0a="" 62="" 6f="" 70=""></buffer></buffer></code>

第一個參數chunk是數據輸入者寫入的數據。第二個參數end是數據的編碼格式。第三個參數next(err)通過回調函數通知數據寫入者可以寫入更多的時間。如果readable stream寫入的是字符串,那么字符串會默認轉換為Buffer,如果在創建流的時候設置Writable({ decodeStrings: false })參數,那么不會做轉換。如果readable stream寫入的數據時對象,那么需要這樣創建writable stream

<code class="hljs css">Writable({ objectMode: true })</code>

2>寫數據到 writable stream

調用writable stream的.write(data)方法即可完成數據寫入。

<code class="hljs vala">process.stdout.write('beep boop\n');</code>

調用.end()方法通知writable stream 數據已經寫入完成。

<code class="hljs javascript">var fs = require('fs');

var ws = fs.createWriteStream('message.txt');

ws.write('beep ');

setTimeout(function () {

ws.end('boop\n');

}, 1000);

$ node writing1.js 

$ cat message.txt

beep boop</code>

如果需要設置writable stream的緩沖區的大小,那么在創建流的時候,需要設置opts.highWaterMark,這樣如果緩沖區里的數據超過opts.highWaterMark,.write(data)方法會返回false。當緩沖區可寫的時候,writable stream會觸發'drain' 事件。

3-4、classic streams

Classic streams比較老的接口了,最早出現在node 0.4版本中,但是了解一下其運行原理還是十分有好

處的。當一個流被注冊了"data" 事件的回到函數,那么流就會工作在老版本模式下,即會使用老的API。

1>classic readable streams

Classic readable streams事件就是一個事件觸發器,如果Classic readable streams有數據可讀取,那么其觸發 "data" 事件,等到數據讀取完畢時,會觸發"end" 事件。.pipe() 方法通過檢查stream.readable 的值確定流是否有數據可讀。下面是一個使用Classic readable streams打印A-J字母的例子:

<code class="hljs javascript">var Stream = require('stream');

var stream = new Stream;

stream.readable = true;

var c = 64;

var iv = setInterval(function () {

if (++c >= 75) {

clearInterval(iv);

stream.emit('end');

}

else stream.emit('data', String.fromCharCode(c));

}, 100);

stream.pipe(process.stdout);

$ node classic0.js

ABCDEFGHIJ</code>

如果要從classic readable stream中讀取數據,注冊"data" 和"end"兩個事件的回調函數即可,代碼如下:

<code class="hljs php">process.stdin.on('data', function (buf) {

console.log(buf);

});

process.stdin.on('end', function () {

console.log('__END__');

});

$ (echo beep; sleep 1; echo boop) | node classic1.js 

<buffer 0a="" 62="" 65="" 70="">

<buffer 0a="" 62="" 6f="" 70="">

__END__</buffer></buffer></code>

需要注意的是如果你使用這種方式讀取數據,那么會失去使用新接口帶來的好處。比如你在往一個 延遲非常大的流寫數據時,需要注意讀取數據和寫數據的平衡問題,否則會導致大量數據緩存在內存中,導致浪費大量內存。一般這時候強烈建議使用流的.pipe()方法,這樣就不用自己監聽”data” 和”end”事件了,也不用擔心讀寫不平衡的問題了。當然你也可以用 through代替自己監聽”data” 和”end” 事件,如下面的代碼:

<code class="hljs php">var through = require('through');

process.stdin.pipe(through(write, end));

function write (buf) {

console.log(buf);

}

function end () {

console.log('__END__');

}

$ (echo beep; sleep 1; echo boop) | node through.js 

<buffer 0a="" 62="" 65="" 70="">

<buffer 0a="" 62="" 6f="" 70="">

__END__</buffer></buffer></code>

或者也可以使用concat-stream來緩存整個流的內容:

<code class="hljs oxygene">var concat = require('concat-stream');

process.stdin.pipe(concat(function (body) {

console.log(JSON.parse(body));

}));

$ echo '{"beep":"boop"}' | node concat.js 

{ beep: 'boop' }</code>

當然如果你非要自己監聽"data" 和"end"事件,那么你可以在寫數據的流不可寫的時候使用.pause()方法暫停Classic readable streams繼續觸發”data” 事件。等到寫數據的流可寫的時候再使用.resume() 方法通知流繼續觸發"data" 事件繼續讀取

數據。

2>classic writable streams

Classic writable streams 非常簡單。只有 .write(buf), .end(buf)和.destroy()三個方法。.end(buf) 方法的buf參數是可選的,如果選擇該參數,相當于stream.write(buf); stream.end() 這樣的操作,需要注意的是當流的緩沖區寫滿即流不可寫時.write(buf)方法會返回false,如果流再次可寫時,流會觸發drain事件。

4、transform

transform是一個對讀入數據過濾然輸出的流。

5、duplex

duplex stream是一個可讀也可寫的雙向流,如下面的a就是一個duplex stream:

<code class="hljs livecodeserver">a.pipe(b).pipe(a)</code>

以上內容是小編給大家介紹的Nodejs Stream 數據流使用手冊,希望對大家有所幫助!

更多信息請查看網絡編程
易賢網手機網站地址:Nodejs Stream 數據流使用手冊
由于各方面情況的不斷調整與變化,易賢網提供的所有考試信息和咨詢回復僅供參考,敬請考生以權威部門公布的正式信息和咨詢為準!

2026上岸·考公考編培訓報班

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關于我們 | 聯系我們 | 人才招聘 | 網站聲明 | 網站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網安備53010202001879號 人力資源服務許可證:(云)人服證字(2023)第0102001523號
云南網警備案專用圖標
聯系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權所有:易賢網
云南網警報警專用圖標
中文字幕免费精品_亚洲视频自拍_亚洲综合国产激情另类一区_色综合咪咪久久
老牛嫩草一区二区三区日本| 中文久久精品| 亚洲精品在线免费| 欧美日韩精品免费看| 99精品免费网| 国产精品视频xxxx| 久久久女女女女999久久| 亚洲高清在线视频| 欧美日韩精品一区| 欧美在线视频观看免费网站| 在线观看日韩av先锋影音电影院| 欧美国产日韩二区| 午夜精品在线看| 91久久国产综合久久蜜月精品| 欧美日韩国产成人高清视频| 亚洲夜间福利| 亚洲电影第1页| 久久久久亚洲综合| 国产日韩欧美麻豆| 亚洲一区二区三区视频播放| 欧美日韩黄色一区二区| 亚洲午夜av在线| 欧美天堂在线观看| 久久精品动漫| 亚洲三级性片| 亚洲高清在线视频| 欧美精品一区在线| 亚洲国产小视频在线观看| 欧美精品99| 久久精品人人做人人爽| 亚洲看片一区| 影音先锋在线一区| 欧美日韩在线第一页| 欧美一区二区成人6969| 日韩午夜高潮| 黄色精品在线看| 国产精品免费电影| 欧美日本韩国| 久久综合图片| 久久福利毛片| 亚洲性色视频| 亚洲最新中文字幕| 最新日韩av| 影音先锋亚洲电影| 国产一区二区丝袜高跟鞋图片| 欧美日韩国产a| 欧美成人一区二区在线| 久久久久一区二区| 久久精品成人| 国产精品久久国产三级国电话系列| 欧美一级视频免费在线观看| 欧美在线播放| 亚洲精品视频啊美女在线直播| 亚洲国产婷婷| 欧美激情久久久| 欧美一区二区三区在线观看视频 | 欧美日韩国产不卡| 久久天堂av综合合色| 日韩午夜在线| 国产精品久久久久久久app| 狠狠色2019综合网| 在线综合亚洲欧美在线视频| 欧美日韩视频在线一区二区| 亚洲视频观看| 亚洲国产导航| 欧美日韩国产高清视频| 国产精品一页| 久久国产精品久久久| 欧美成人三级在线| 亚洲激情视频在线| 一区二区三区在线免费观看| 亚洲国产精品成人| 亚洲免费在线视频一区 二区| 久久久www| 欧美日韩综合不卡| 亚洲国产精品999| 欧美一区二区三区视频免费| 欧美日韩大片| 亚洲福利电影| 久久久精品久久久久| 国产精品乱码妇女bbbb| 亚洲免费观看视频| 女同一区二区| 亚洲大胆av| 久久夜色精品国产亚洲aⅴ| 国产欧美日本在线| 亚洲欧美在线另类| 国产精品一卡| 亚洲综合欧美日韩| 欧美体内she精视频| 亚洲精品一区二区三区在线观看 | 久久久久久电影| 国产精品午夜在线| 亚洲小少妇裸体bbw| 欧美日韩国产综合视频在线观看中文| 在线日韩精品视频| 久久青青草综合| 伊人久久大香线蕉av超碰演员| 欧美一区三区二区在线观看| 国产精品户外野外| 亚洲欧美日韩成人| 国产精品入口夜色视频大尺度| 这里只有精品视频在线| 国产精品久久精品日日| 午夜一区二区三区在线观看| 国产人成一区二区三区影院| 欧美在线观看一区| 经典三级久久| 欧美成人视屏| 一本大道久久精品懂色aⅴ| 欧美日韩久久久久久| 亚洲私人影院在线观看| 国产精品乱码一区二区三区| 亚洲综合导航| 国产亚洲人成a一在线v站| 久热成人在线视频| 日韩亚洲在线| 国产精品专区第二| 久久男人资源视频| 日韩午夜在线| 国产精品日本一区二区| 久久人人看视频| 亚洲精品综合在线| 国产欧美欧美| 欧美成人精品一区二区| 亚洲色图在线视频| 国语自产精品视频在线看8查询8 | 欧美日韩在线一区| 欧美一区二区大片| 亚洲激情另类| 国产精品嫩草久久久久| 久久精品一区四区| 亚洲毛片在线| 国产一区二区三区精品欧美日韩一区二区三区 | 性欧美激情精品| 精品电影在线观看| 欧美日韩国产一中文字不卡| 欧美一区日韩一区| 日韩小视频在线观看| 国产日韩av一区二区| 欧美高清成人| 久久riav二区三区| 一区二区三区波多野结衣在线观看| 国产亚洲欧洲一区高清在线观看| 欧美成人一区在线| 久久精品国产第一区二区三区| 99视频国产精品免费观看| 狠狠色2019综合网| 国产精品揄拍一区二区| 欧美日韩国产美| 久久久999成人| 亚洲免费中文字幕| 99国产精品私拍| 在线精品一区| 国产一二三精品| 欧美日韩午夜精品| 亚欧成人在线| 欧美在线免费一级片| 国产一区在线播放| 欧美精品一区二区三区高清aⅴ| ●精品国产综合乱码久久久久| 久久手机精品视频| 亚洲天堂网站在线观看视频| 国产精品永久免费视频| 久久性色av| 亚欧美中日韩视频| 香蕉视频成人在线观看| 欧美成人有码| 久久久久在线| 欧美一站二站| 亚洲午夜久久久| 日韩午夜激情电影| 最新国产成人在线观看| 狠狠色噜噜狠狠狠狠色吗综合| 国产九九精品| 国产欧美午夜| 国产欧美精品xxxx另类| 国产精品成av人在线视午夜片| 欧美日韩视频| 欧美调教vk| 国产精品裸体一区二区三区| 国产精品福利在线| 欧美午夜片在线观看| 国产精品久久影院| 国产女主播一区二区| 国产欧美一区二区白浆黑人| 国产精品一区二区三区四区| 国产精品日韩高清| 国产欧美高清| 国内视频精品| 亚洲国产裸拍裸体视频在线观看乱了中文| 黄色精品在线看| 亚洲人成网站999久久久综合| 亚洲激情啪啪| 一区二区欧美视频| 午夜一区二区三区在线观看| 久久国产精品亚洲va麻豆| 久久网站热最新地址| 欧美黄色一区| 国产精品亚洲精品|