NodeAPI學習之Stream

Stream

流能夠是可讀的、可寫的、或者是可讀寫的。全部的流都是EventEmitter的實例。javascript

對象模式

全部使用Node.js API建立的流對象都只能操做strings和Buffer(或Unit8Array)。可是一些第三方流的實現,可以操做其餘類型的javascript值(除了null,它在流處理中有特殊意義),這種類型的流被認爲是工做在‘對象模式’java

緩衝

Writable和Readable流都會將數據存儲到內部的緩存(buffer)中緩存

  • 可讀流的實現調用stream.push(chunk)時,數據被放到緩存中。若是流的消費者沒有調用stream.read()方法,就會始終存在於內部隊列中,直到被消費。緩存的大小取決於傳遞給流構造函數的highWaterMark選項。當內部可讀緩存的大小達到highWaterMark指定的閥值時,流會暫停從底層資源讀取數據,直到當前緩存的數據被消費。
  • 可寫流經過反覆調用writable.write(chunk)方法將數據放到緩存。當內部可寫緩存的總大小小於highWaterMark指定的閥值時,調用writable.write()返回true,一旦達到或超過highWaterMark,調用writable.write()返回false,此時應該中止向流中寫入數據,直到drain事件被觸發。

可讀的流Readable

例如fs.createReadStream()函數

可讀流(Readable streams)是對提供數據的源頭(source)的抽象ui

兩種工做模式:flowing(流動模式)和paused(暫停模式)code

  • flowing模式下:可讀流自動從系統底層讀取數據,並經過EventEmitter()接口的事件儘快將數據提供給應用。
  • paused模式下:必須顯式調用stream.read()方法來從流中讀取數據片斷。

初始工做模式都是paused的Readable流,能夠經過三種途徑切換到flowing模式。orm

  • 監聽data事件
  • 調用stream.resume()方法
  • 調用stream.pipe()方法將數據發送到Writable

可讀流能夠經過兩種方式切換到paused對象

  • 若是可讀流沒有橋接可寫流成爲管道,調用stream.pause()實現
  • 若是可讀流橋接了若干可寫流組成了管道,經過取消data事件監聽,並調用stream.unpipe()方法移除全部管道目標實現
  • close事件:

在流或其底層資源(好比一個文件)關閉後觸發。事件觸發後,該流將不會再觸發任何事件。接口

  • data事件:

在流將數據傳遞給消費者時觸發。當流轉換到flowing模式時會觸發該事件。處理器的參數是Buffer對象,若是你調用了Readable的setEncoding(encoding)方法,處理器的參數就是String對象。隊列

  • end事件:

在流中再沒有數據可供消費時觸發。

const readable = readableStreamSomehow()
readable.on('data', (chunk) => {
    console.log(`received ${chunk.length} bytes of buffer data.`)
})
readable.on('end', () => {
    console.log('no more data.')
})
  • error事件:

一般底層系統內部出錯從而不能產生數據,或當流的實現試圖傳遞錯誤數據時發生。回調函數將接收到一個Error對象。

  • readable事件:

將在流中有數據可供讀取時觸發。stream.read()返回可用的數據。

const readable = readableStreamSomehow()
readable.on('readable', () => {
    // 有一些數據可讀
})

在到達流數據尾部時,該事件也會觸發。觸發順序在end事件以前。stream.read()返回null

// foo.txt是一個空文件
const fs = require('fs')
const rr = fs.createReadStream('foo.txt')
rr.on('readable', () => {
    console.log('readable', rr.read) // null
})
rr.on('end', () => {
    console.log('end') // end
})
  • readable.pipe(destination[,options])

綁定一個writable到readable上,造成一個管道,並將全部數據傳給綁定的writable。能夠在單個可讀流上綁定多個可寫流。

const r = fs.createReadStream('file.txt')
const z = zlib.createGzip()
const w = fs.createWriteStream('file.txt.gz')
r.pipe(z).pipe(w)

默認狀況下,當源可讀流觸發end事件時,目標流也會調用stream.end()方法從而結束寫入。要禁止這一默認行爲,end選項應該指定爲false。

reader.pipe(writer, {end: false})
reader.on('end', () => {
    writer.end('goodbye)
})

若是可讀流在處理時發生錯誤,目標可寫流不會自動關閉。 若是發生錯誤,須要手動關閉全部流以免內存泄漏。

通常來講,建議開發人員避免使用'readable'事件和readable.read()方法,使用readable.pipe()或'data'事件代替。

  • writable.unpipe([destination])

readable.unpipe()方法將以前經過stream.pipe()方法綁定的流分離

若是 destination 沒有傳入, 則全部綁定的流都會被分離.

若是傳入 destination, 但它沒有被pipe()綁定過,則該方法不做爲.

可寫的流Writable

例如fs.createWriteStream()

Writable streams是destination的一種抽象,這種destination容許數據寫入

  • close事件:

在流或者底層資源(好比一個文件)關閉後觸發,事件觸發後該流將不會再觸發任何事件。

  • drain事件`:

若是調用stream.write(chunk)方法返回false,流將在適當的時機觸發drain事件,這時才能夠繼續向流中寫入數據。

  • error事件`:

在寫入數據出錯或者使用管道(pipe)出錯時觸發,事件發生時,回調函數僅會接收到一個Error參數。注意:error事件發生時,流並不會關閉。

  • finish事件

在調用了stream.end()方法,且緩衝區數據都已經傳給底層系統以後,finish事件將被觸發。

  • pipe事件

在可讀流上調用stream.pipe()方法,並在目標流向中添加當前可寫流時,將會在可寫流上觸發pipe事件。

const writer = writeStreamSomehow()
const reader = readStreamSomehow()
writer.on('pipe', (src) => {
    console.log('piping into the writer')
    assert.equal(src, reader)
})
reader.pipe(writer)
  • writable.end([chunk][,encoding][,callback])

調用writable.end()方法代表接下來沒有數據要被寫入writable,經過傳入可選的chunk和encoding參數,能夠在關閉流以前再寫入一段數據。若是傳入了可選的callback函數,將做爲finish事件的回掉函數。

在調用了stream.end()方法以後,再調用stream.write()方法會致使錯誤。

// 寫入hello 並用world結束寫入
const file = fs.createWriteStream('example.txt)
file.write('hello, ')
file.end('wrold!)
// 後面不容許再寫入數據
  • writable.write(chunk[,encoding][,callback])

向流中寫入數據,並在數據處理完成後調用callback。咱們建議,一旦write()返回false,在'drain'事件觸發前,不能寫入任何數據塊。

  • writable.uncork()

可讀寫的流Duplex

例如net.Socket()

在讀寫過程當中能夠修改和變換數據的Duplex流Transform

例如zlib.createDeflate()

相關文章
相關標籤/搜索