Node.js內(nèi)置的fs模塊就是文件系統(tǒng)模塊,負(fù)責(zé)讀寫(xiě)文件。
和所有其它JavaScript模塊不同的是,fs模塊同時(shí)提供了異步和同步的方法。
回顧一下什么是異步方法。
- 因?yàn)镴avaScript的單線程模型,執(zhí)行IO操作時(shí),JavaScript代碼無(wú)需等待,而是傳入回調(diào)函數(shù)后,繼續(xù)執(zhí)行后續(xù)JavaScript代碼。
// 獲取遠(yuǎn)程 json 數(shù)據(jù)
$.getJSON('http://example.com/ajax', function (data) { console.log('IO結(jié)果返回后執(zhí)行...');});
console.log('不等待IO結(jié)果直接執(zhí)行后續(xù)代碼...');
- 而同步的IO操作則需要等待函數(shù)返回:
// 根據(jù)網(wǎng)絡(luò)耗時(shí),函數(shù)將執(zhí)行幾十毫秒~幾秒不等:
// 獲取遠(yuǎn)程 json 數(shù)據(jù)
var data = getJSONSync('http://example.com/ajax');
同步操作的好處是代碼簡(jiǎn)單,缺點(diǎn)是程序?qū)⒌却齀O操作,在等待時(shí)間內(nèi),無(wú)法響應(yīng)其它任何事件。而異步讀取不用等待IO操作,但代碼較麻煩。
異步讀文件
異步讀取文件使用的是 fs 模塊中的 readFile 方法。
手冊(cè)地址
https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback
最起碼 要傳入兩個(gè)參數(shù)
- 文件路徑
- 回調(diào)方法
先創(chuàng)建一個(gè) sample.txt 文本,內(nèi)容如下
黃河遠(yuǎn)上白云間,一片孤城萬(wàn)仞山。
羌笛何須怨楊柳,春風(fēng)不度玉門(mén)關(guān)。
創(chuàng)建讀取腳本 fs.js
// 引入文件系統(tǒng)管理模塊
const FS = require('fs');
// 讀取文件
FS.readFile('sample.txt', 'utf-8', function (err, data) {
console.log("\n ====== 讀取文件內(nèi)容 \n");
// 如果報(bào)錯(cuò)的話就打印 錯(cuò)誤
if (err) {
console.log(err);
// 如果沒(méi)有錯(cuò)誤的話 就輸出內(nèi)容
} else {
console.log(data.toString());
}
console.log("\n");
});
// 當(dāng)正常讀取時(shí),err參數(shù)為null,data參數(shù)為讀取到的String。
// 傳入的回調(diào)函數(shù)接收兩個(gè)參數(shù),err 和 data
// 當(dāng)讀取發(fā)生錯(cuò)誤時(shí),err參數(shù)代表一個(gè)錯(cuò)誤對(duì)象,data為undefined。
// 這也是Node.js標(biāo)準(zhǔn)的回調(diào)函數(shù):第一個(gè)參數(shù)代表錯(cuò)誤信息,第二個(gè)參數(shù)代表結(jié)果。后面我們還會(huì)經(jīng)常編寫(xiě)這種回調(diào)函數(shù)。
同步讀文件
除了標(biāo)準(zhǔn)的異步讀取模式外,fs也提供相應(yīng)的同步讀取函數(shù)。同步讀取的函數(shù)和異步函數(shù)相比,多了一個(gè)Sync后綴,并且不接收回調(diào)函數(shù),函數(shù)直接返回結(jié)果。
案例
var fs = require('fs');var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);
異步寫(xiě)文件
將數(shù)據(jù)寫(xiě)入文件是通過(guò)fs.writeFile()實(shí)現(xiàn)的
文檔地址
https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
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編碼寫(xiě)入文本文件,如果傳入的參數(shù)是Buffer,則寫(xiě)入的是二進(jìn)制文件。
- 回調(diào)函數(shù)由于只關(guān)心成功與否,因此只需要一個(gè)err參數(shù)。
同步寫(xiě)文件
同步寫(xiě)入文件是通過(guò)fs.writeFileSync()實(shí)現(xiàn)的
文檔地址
https://nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
var fs = require('fs');
var data = 'Hello, Node.js';
fs.writeFileSync('output.txt', data);
獲取文件信息 stat
如果我們要獲取文件大小,創(chuàng)建時(shí)間等信息,可以使用fs.stat(),它返回一個(gè)Stat對(duì)象,能告訴我們文件或目錄的詳細(xì)信息:
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());
// 如果是文件 答應(yīng)文件信息
if (stat.isFile()) {
// 文件大小:
console.log('size: ' + stat.size);
// 創(chuàng)建時(shí)間, Date對(duì)象:
console.log('birth time: ' + stat.birthtime);
// 修改時(shí)間, Date對(duì)象:
console.log('modified time: ' + stat.mtime);
}
}
});
stat 也有一個(gè)同步的函數(shù) statSync
var fs = require('fs');
var data = fs.statSync('sample.txt');
console.log(data);
異步還是同步
在fs 模塊中,提供同步方法是為了方便使用。那我們到底是應(yīng)該用異步方法還是同步方法呢?
由于Node環(huán)境執(zhí)行的JavaScript代碼是服務(wù)器端代碼,所以,絕大部分需要在服務(wù)器運(yùn)行期反復(fù)執(zhí)行業(yè)務(wù)邏輯的代碼,必須使用異步代碼,否則,同步代碼在執(zhí)行時(shí)期,服務(wù)器將停止響應(yīng),因?yàn)镴avaScript只有一個(gè)執(zhí)行線程。
服務(wù)器啟動(dòng)時(shí)如果需要讀取配置文件,或者結(jié)束時(shí)需要寫(xiě)入到狀態(tài)文件時(shí),可以使用同步代碼,因?yàn)檫@些代碼只在啟動(dòng)和結(jié)束時(shí)執(zhí)行一次,不影響服務(wù)器正常運(yùn)行時(shí)的異步執(zhí)行。