fs文件讀取模塊
Node.js內(nèi)置的fs模塊就是文件系統(tǒng)模塊,負(fù)責(zé)讀寫文件。
和所有其它JavaScript模塊不同的是,fs模塊同時提供了異步和同步的方法。
1 異步讀文件
按照J(rèn)avaScript的標(biāo)準(zhǔn),異步讀取一個文本文件的代碼如下:
'use strict';
var fs = require('fs');
fs.readFile('sample.txt', 'utf-8', function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
請注意,sample.txt文件必須在當(dāng)前目錄下,且文件編碼為utf-8。
異步讀取時,傳入的回調(diào)函數(shù)接收兩個參數(shù),當(dāng)正常讀取時,err參數(shù)為null,data參數(shù)為讀取到的String。當(dāng)讀取發(fā)生錯誤時,err參數(shù)代表一個錯誤對象,data為undefined。這也是Node.js標(biāo)準(zhǔn)的回調(diào)函數(shù):第一個參數(shù)代表錯誤信息,第二個參數(shù)代表結(jié)果。后面我們還會經(jīng)常編寫這種回調(diào)函數(shù)。
由于err是否為null就是判斷是否出錯的標(biāo)志,所以通常的判斷邏輯總是:
if (err) {
// 出錯了
} else {
// 正常
}
如果我們要讀取的文件不是文本文件,而是二進(jìn)制文件,怎么辦?
下面的例子演示了如何讀取一個圖片文件:
'use strict';
var fs = require('fs');
fs.readFile('sample.png', function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data);
console.log(data.length + ' bytes');
}
});
當(dāng)讀取二進(jìn)制文件時,不傳入文件編碼時,回調(diào)函數(shù)的data參數(shù)將返回一個Buffer對象。在Node.js中,Buffer對象就是一個包含零個或任意個字節(jié)的數(shù)組(注意和Array不同)。
Buffer對象可以和String作轉(zhuǎn)換,例如,把一個Buffer對象轉(zhuǎn)換成String:
// Buffer -> String
var text = data.toString('utf-8');
console.log(text);
或者把一個String轉(zhuǎn)換成Buffer:
// String -> Buffer
var buf = new Buffer(text, 'utf-8');
console.log(buf);
2 同步讀文件
除了標(biāo)準(zhǔn)的異步讀取模式外,fs也提供相應(yīng)的同步讀取函數(shù)。同步讀取的函數(shù)和異步函數(shù)相比,多了一個Sync后綴,并且不接收回調(diào)函數(shù),函數(shù)直接返回結(jié)果。
用fs模塊同步讀取一個文本文件的代碼如下:
'use strict';
var fs = require('fs');
var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);
可見,原異步調(diào)用的回調(diào)函數(shù)的data被函數(shù)直接返回,函數(shù)名需要改為readFileSync,其它參數(shù)不變。
如果同步讀取文件發(fā)生錯誤,則需要用try...catch捕獲該錯誤:
try {
var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);
} catch (err) {
// 出錯了
}
3 寫文件
將數(shù)據(jù)寫入文件是通過fs.writeFile()實現(xiàn)的:
'use strict';
var fs = require('fs');
var data = 'Hello, Node.js';
fs.writeFile('output.txt', data, function (err) {
if (err) {
console.log(err);
} else {
console.log('ok.');
}
});
writeFile()的參數(shù)依次為文件名、數(shù)據(jù)和回調(diào)函數(shù)。如果傳入的數(shù)據(jù)是String,默認(rèn)按UTF-8編碼寫入文本文件,如果傳入的參數(shù)是Buffer,則寫入的是二進(jìn)制文件?;卣{(diào)函數(shù)由于只關(guān)心成功與否,因此只需要一個err參數(shù)。
和readFile()類似,writeFile()也有一個同步方法,叫writeFileSync():
'use strict';
var fs = require('fs');
var data = 'Hello, Node.js';
fs.writeFileSync('output.txt', data);
stat
如果我們要獲取文件大小,創(chuàng)建時間等信息,可以使用fs.stat(),它返回一個Stat對象,能告訴我們文件或目錄的詳細(xì)信息:
'use strict';
var fs = require('fs');
fs.stat('sample.txt', function (err, stat) {
if (err) {
console.log(err);
} else {
// 是否是文件:
console.log('isFile: ' + stat.isFile());
// 是否是目錄:
console.log('isDirectory: ' + stat.isDirectory());
if (stat.isFile()) {
// 文件大小:
console.log('size: ' + stat.size);
// 創(chuàng)建時間, Date對象:
console.log('birth time: ' + stat.birthtime);
// 修改時間, Date對象:
console.log('modified time: ' + stat.mtime);
}
}
});
運行結(jié)果如下:
isFile: true
isDirectory: false
size: 181
birth time: Fri Dec 11 2015 09:43:41 GMT+0800 (CST)
modified time: Fri Dec 11 2015 12:09:00 GMT+0800 (CST)
stat()也有一個對應(yīng)的同步函數(shù)statSync(),請試著改寫上述異步代碼為同步代碼。
4 異步還是同步
在fs模塊中,提供同步方法是為了方便使用。那我們到底是應(yīng)該用異步方法還是同步方法呢?
由于Node環(huán)境執(zhí)行的JavaScript代碼是服務(wù)器端代碼,所以,絕大部分需要在服務(wù)器運行期反復(fù)執(zhí)行業(yè)務(wù)邏輯的代碼,==必須使用異步代碼==,否則,同步代碼在執(zhí)行時期,服務(wù)器將停止響應(yīng),因為JavaScript只有一個執(zhí)行線程。
服務(wù)器啟動時如果需要讀取配置文件,或者結(jié)束時需要寫入到狀態(tài)文件時,可以使用同步代碼,因為這些代碼只在啟動和結(jié)束時執(zhí)行一次,不影響服務(wù)器正常運行時的異步執(zhí)行。