首頁 > web前端 > js教程 > 主體

Node.js Streams檔案讀寫操作詳解

高洛峰
發布: 2016-12-28 13:17:01
原創
1442 人瀏覽過

Node.js 天生非同步和事件驅動,非常適合處理 I/O 相關的任務。如果你在處理應用程式中 I/O 相關的操作,你可以利用 Node.js 中的流(stream)。因此,我們先具體看看流,理解一下它們是怎麼簡化 I/O 操作的吧。 

流是什麼
流是 unix 管道,讓你可以輕鬆地從資料來源讀取數據,然後流向另一個目的地。
簡單來說,串流不是什麼特別的東西,它只是一個實作了一些方法的 EventEmitter 。根據它實作的方法,流可以變成可讀流(Readable),可寫流(Writable),或雙向流(Duplex,同時可讀可寫)。
可讀流能讓你從一個資料來源讀取數據,而可寫入流則可以讓你往目的地寫入資料。
如果你已經用過 Node.js,你很可能已經遇到過流了。
例如,在一個 Node.js 的 HTTP 伺服器裡面, request 是一個可讀流, response 是可寫流。
你也可能用過 fs 模組,它能幫你處理可讀可寫流。
 現在讓你學一些基礎,理解不同類型的流。本文會討論可讀流和可寫流,雙向流超出了本文的討論範圍,我們不作討論。
 可讀流 (Readable Streams)
 我們可以用可讀流從一個資料來源讀取數據,這個資料來源可以是任何東西,例如係統中的一個文件,記憶體中的 buffer,甚至是其他流。因為串流是 EventEmitter ,它們會用各種事件發送資料。我們會利用這些事件來讓流運作。

從流中讀取資料
 從流中讀取資料最好的方式是監聽 data 事件,增加一個回調函數。當有資料流過來的時候,可讀流會發送 data 事件,回呼函數就會觸發。看看下面的程式碼片段:

var fs = require('fs');
var readableStream = fs.createReadStream('file.txt');
var data = '';
 
var readableStream.on('data', function(chunk){
 data += chunk;
});
 
readableStream.on('end', function(){
 console.log(data);
});
登入後複製

fs.createReadStream 會給你一個可讀流。
最開始的時候,這個流不是流動態的。當你加入了 data 的事件監聽器,加上一個回呼函數時,它才會變成流動態的。在這之後,它就會讀取一小塊數據,然後傳到你的回呼函數裡面。
流的實作者決定了 data 事件的觸發頻率,例如 HTTP request 會在讀取到幾 KB 資料的時候觸發 data 事件。 當你從一個檔案讀取資料的時候,你可能會決定當一行被讀完的時候就觸發 data 事件。
當沒有資料可讀的時候 (讀到文件尾部時),流就會發送 end 事件。在上面的例子中,我們監聽了這個事件,當讀完文件的時候,就把資料列印出來。
還有另一種讀取流的方式,你只要在讀到檔案尾部前不斷呼叫流實例中的 read() 方法就可以了。

var fs = require('fs');
var readableStream = fs.createReadStream('file.txt');
var data = '';
var chunk;
 
readableStream.on('readable', function(){
 while ((chunk = readableStream.read()) != null) {
 data += chunk;
 }
});
 
readableStream.on('end', function(){
 console.log(data);
});
登入後複製

read() 方法會從內部 buffer 中讀取數據,當沒有數據可讀的時候,它會傳回 null 。
因此,在 while 迴圈中我們檢查 read() 是不是回傳 null ,當它回傳 null 的時候,就終止迴圈。
要注意的是,當我們可以從流讀取資料的時候, readable 事件就會被觸發。
設定編碼
預設情況下,你從流中讀取到的是 Buffer 物件。如果你要讀取的是字串的話,這並不適合你。因此,你可以像下面的範例一樣透過呼叫Readable.setEncoding() 來設定流的編碼:

var fs = require('fs');
var readableStream = fs.createReadStream('file.txt');
var data = '';
 
readableStream.setEncoding('utf8');
 
readableStream.on('data', function(chunk){
 data += chunk;
});
 
readableStream.on('end', function(){
 console.log(data);
});
登入後複製

上面的例子中,我們把流的編碼設定成utf8 ,資料就會被解析成utf8 ,回呼函數中的chunk 就會是字串了。
管道 (Piping)
管道是一個很棒的機制,你不需要自己管理流的狀態就可以從數據源中讀取數據,然後寫入目的地。我們先來看看下面的範例:

var fs = require('fs');
var readableStream = fs.createReadStream('file1.txt');
var writableStream = fs.createWriteStream('file2.txt');
 
readableStream.pipe(writableStream);
登入後複製

上面的範例利用 pipe() 方法把 file1 的內容寫到 file2 中。因為 pipe() 會幫你管理資料流,你不需要擔心資料流的速度。這讓 pipe() 變得非常簡潔易用。
需要注意的是, pipe() 會返回目的地的流,因此你可以輕鬆地讓多個流連結起來!
連結 (Chaining)
假設有一個歸檔文件,你想要解壓縮它。有很多方式可以完成這個任務。但最簡潔的方式是利用管道和連結:

var fs = require('fs');
var zlib = require('zlib');
 
fs.createReadStream('input.txt.gz')
 .pipe(zlib.createGunzip())
 .pipe(fs.createWriteStream('output.txt'));
登入後複製

首先,我們透過 input.txt.gz 創建了一個可讀流,然後讓它流 zlib.createGunzip() 流,它會解壓縮內容。最後,我們加入一個可寫流把解壓縮後的內容寫到另一個文件中。
其他方法
 我們已經討論了一些可讀流中重要的概念了,這裡還有一些你需要知道的方法:
 1.Readable.pause() – 這個方法會暫停流的流動。換句話說就是它不會再觸發 data 事件。
 2.Readable.resume() – 這個方法和上面的相反,會讓暫停流恢復流動。
 3.Readable.unpipe() – 這個方法會把目的地移除。如果有參數傳入,它會讓可讀流停止劉翔某個特定的目的地,否則,它會移除所有目的地。 

可写流 (Writable Streams)
可写流让你把数据写入目的地。就像可读流那样,这些也是 EventEmitter ,它们也会触发不同的事件。我们来看看可写流中会触发的事件和方法吧。
写入流
要把数据写如到可写流中,你需要在可写流实例中调用 write() 方法,看看下面的例子:

var fs = require('fs');
var readableStream = fs.createReadStream('file1.txt');
var writableStream = fs.createWriteStream('file2.txt');
 
readableStream.setEncoding('utf8');
 
readableStream.on('data', function(chunk){
 writableStream.write('chunk');
});
登入後複製

上面的代码非常简单,它只是从输入流中读取数据,然后用 write() 写入到目的地中。
 这个方法返回一个布尔值来表示写入是否成功。如果返回的是 true 那表示写入成功,你可以继续写入更多的数据。 如果是 false ,那意味着发生了什么错误,你现在不能继续写入了。可写流会触发一个 drain 事件来告诉你你可以继续写入数据。
 写完数据后
 当你不需要在写入数据的时候,你可以调用 end() 方法来告诉流你已经完成写入了。假设 res 是一个 HTTP response 对象,你通常会发送响应给浏览器:
res.write('Some Data!!');
res.end();
当 end() 被调用时,所有数据会被写入,然后流会触发一个 finish 事件。注意在调用 end() 之后,你就不能再往可写流中写入数据了。例如下面的代码就会报错:
res.write('Some Data!!');
res.end();
res.write('Trying to write again'); //Error !
这里有一些和可写流相关的重要事件:
 1.error – 在写入或链接发生错误时触发
 2.pipe – 当可读流链接到可写流时,这个事件会触发
 3.unpipe – 在可读流调用 unpipe 时会触发

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。

更多Node.js Streams文件读写操作详解相关文章请关注PHP中文网!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!