Node之IO

Buffer

Buffer的構成

Buffer對象類似數組,它的元素位16進制的兩位數,即0到255的數值。主要是用來存儲二進制的數據

const buf = Buffer.from('Hello world')

初始化Buffer會隨機的填充了0到255的隨機值

var buffer = new Buffer(100);
buffer[20] = -100;

console.log(buffer[20]) // 如果存儲的數字小于0或者大于255則直接加值256知道值位于0到255之間

Buffer的底層分配

Node從c++層面申請內存,在JS層面用來分配內存的策略,Buffer在C++申請內存主要是8K。

Buffer的轉換

目前Buffer的對象是可以直接與字符串進行互相轉換,目前支持的字符串編碼類型有

  • ASCII

  • UTF-8

  • UTF-16

  • Base64

  • Binary

  • Hex

    目前官方暫時不支持漢字編碼GBK之類,如果有類似的漢字編碼需求需要調用第三方庫的支持。

Buffer的亂碼現象

因為Buffer對象只要是用于二進制與字符串的轉換,一旦設計編碼 解碼就會出現所謂的亂碼現象,特別是出現在漢字編碼問題。

var rs = fs.createReadStream('buffer.txt',{
  highWaterMark:11
});

var data = '';
rs.on('data',(thunk)=>{
  data +=thunk; // data.toString() += thunk.toString()
})

rs.on('end',()=>{
  console.log(data);
})

在Options上選擇了highWaterMark,主要是影響操作系統讀取文件的字節塊,目前是按照11字節讀取,因為漢字在UTF-8中編碼只要是三個字節,所以在讀取漢字的時候可能會出現兩個字節導致無法編碼,出現所謂的亂碼現象。

亂碼解決方案

  • stream.setEncoding('utf-8') 這樣當stream讀取到中文漢字需要解碼的時候 底層的string_decoder 則會收集完整的字節然后解碼顯示漢字
  • 通過將stream中的數據接受完整數據后,然后指定編碼符來統一解碼。

Stream

Node.js中有四種基本的流類型:

  • Readable 可讀的流(例如 fs.createReadStream())
  • Writable 可寫的流 (例如 fs.createWriteStream())
  • Duplex 可讀寫的流 ( 例如 net.Socket)
  • Transform 在讀寫過程中科院修改和變換數據的Duplex流

緩沖

Writable和Readable流都會將數據存儲到內部的緩存中。這些緩存可以通過相應的writable._writableState.getBuffer()或者readable._readableState.buffer來獲取。 緩存的大小取決流構造函數的highWaterMark選項。對于普通的流, highWaterMark選項指定了總共的字節數。對于工作在對象模式的流,highWaterMark指定了對象的總數。

  • 當可讀流實現調用了stream.push(chunk)方法,數據被放到了緩存中,如果流的消費者沒有調用stream.read()方法,這些數據會始終存在內部隊列,直到被消費。
  • 可寫流通過反復調用writable.write(chunk)方法將數據放到緩存。當內部可寫入緩存的總大小小于highWaterMark指定的閥值,調用writable.write()將返回true.
  • streamAPI的關鍵方法在于stream.pipe()方法,就是限制緩存數據大小,以達到可接受的程度。這樣,對于讀寫速度不匹配的源頭和目標。

可寫流

Write Streams 是destination的一種抽象,這種destination允許數據寫入

Writable的例子包括了

  • HTTP request, on the client
  • HTTP response, on the server
  • fs write streams
  • lib streams
  • crypto streams
  • TCP sockets
  • child process stdin

Writeable流暴露了一些方法 比如write() end() pipe()方法

Writable類的事件和方法

  • close事件 底層資源關閉后觸發 close事件觸發后,該流將不會再觸發任何事件
  • drain 事件 當stream.write(chunk)方法返回false 出發 此時才能繼續讓緩沖區寫入數據
  • error事件 stream寫入數據出錯
  • finish 事件 stream.end()方法
  • pipe 事件 輸出到目標可寫入流的源流 stream.pipe() 方法
  • writable.cork() 強制將所有寫入數據源都放入內存中的緩沖區
  • writable.end(chunk, encoding, callback)
  • writable.setDefaultEncoding
  • writable.write(chunk,encoding,callback)
  • writable.destroy(error)

可讀流

Readable的例子

  • HTTP response, on the client
  • HTTP request , on the server
  • fs read streams
  • zlib streams
  • crypto streams
  • TCP sockets
  • child process stdin

可讀流的時間和方法

  • close事件
  • data事件
  • end事件
  • error事件
  • readable.pause()
  • readable.pipe()
  • readable.unpipe()
  • readable.setEncoding(encoding)
  • readable.destory(error)

兩種模式

可讀流事實上工作在下面兩種模式之一: flowing 和paused

在flowing模式下,可讀流自動從系統底層讀取數據,并通過EventEmitter接口的事件盡快將數據提供給應用

在paused模式下,必須顯示調用stream,read()方法來從流中讀取數據片段

所有初始工作位paused的Readable流,可以通過下面三種途徑切換到flowing模式:

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

從Flowing模式切換到paused模式

  • 如果存在了管道目標,可以通過取消'data'事件箭筒,并調用stream.unpipe()方法移除所有管道目標來實現
  • 如果不存在管道目標,直接調用stream.pause()方法來實現

三種狀態

任意可讀流應確切處于下面三種狀態:

  • readable._readableState.flowing = null

    由于不存在數據消費者,可讀流將不會產生數據

  • readable._readableState.flowing = false

    調用 readable.pause() 方法, readable.unpipe() 方法, 或者接收 “背壓”(back pressure), 將導致 readable._readableState.flowing 值變為 false。 這將暫停事件流,但 不會 暫停數據生成。

  • readable._readableState.flowing = true

    當stream監聽了 'data'事件 調用了pipe方法,或者調用readable.resume()方法

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • stream 流是一個抽象接口,在 Node 里被不同的對象實現。例如 request to an HTTP se...
    明明三省閱讀 3,424評論 1 10
  • 流是Node中最重要的組件和模式之一。在社區里有一句格言說:讓一切事務流動起來。這已經足夠來描述在Node中流...
    宮若石閱讀 572評論 0 0
  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測試 ...
    KeKeMars閱讀 6,366評論 0 6
  • 為什么應該使用流 你可能看過這樣的代碼。 這段代碼中,服務器每收到一次請求,就會先把data.txt讀入到內存中,...
    饑人谷_xxxxx閱讀 10,835評論 1 12
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,837評論 18 139