文章目錄
上一篇文章我們介紹了nodejs的事件,如新建或繼承事件對象,綁定事件對象等,詳見: Node.js後端開發 - 基礎篇 #5 事件 這篇文章我們將介紹nodejs的讀寫文件(同步,異步),那麼怎麼讀寫文件?怎麼把文件的內容讀取出來,然後再把它寫到另一個文件中,並且通過這篇文章我們來簡單理解同步和異步的關係。好了廢話少說,我們來開始編碼!
同步
readFileSync方法
我們可以在app.js裏面寫入以下代碼:
//導入nodejs文件系統的一個庫
var fs = require('fs');
//參數1:文件名路徑,路徑需要加雙引號。
//因爲是當前目錄,所以直接可以寫文件名
//參數2:編碼格式
var readMe = fs.readFileSync("readMe.txt","utf-8");
我們手動新建一個文件readMe.txt,寫入內容:讀我啊 read me
我們來看一看讀取出來的結果:
MacBook-Pro:hello-nodejs luminal$ node app
讀我啊 read me
MacBook-Pro:hello-nodejs luminal$
writeFileSync方法
下面我們來看看寫的方法,代碼如下:
var fs = require('fs');
var readMe = fs.readFileSync("readMe.txt","utf-8");
//參數1:要寫入的文件名路徑。沒有的話,它會自動新建
//參數2:要寫入的內容。
fs.writeFileSync("writeMe.txt", readMe);
//fs.writeFileSync("writeMe.txt", "190910馬老師-怒放的生命");
我們來看看輸出結果:
MacBook-Pro:hello-nodejs luminal$ node app
MacBook-Pro:hello-nodejs luminal$
因爲是寫入操作,我們沒有日誌輸出,下面我們會發現當前目錄,自動生成了一個 writeMe.txt 的文件
上面是把 readMe 這個對象的內容寫進去了。
當然你也可以自定義內容寫進去 fs.writeFileSync("writeMe.txt", "190910馬老師-怒放的生命"); 這個結果就不貼圖了!
異步
readFile方法
上面演示的 readFileSync、writeFileSync都是同步方法,其實sync英文就是同步的意思,那麼有同步就必然有異步,下面我們來看看下面的代碼
var fs = require('fs');
var readMe = fs.readFileSync("readMe.txt","utf-8");
console.log(readMe);
console.log("finished");
我們來看看輸出結果:
MacBook-Pro:hello-nodejs luminal$ node app
讀我啊 read me
finished
MacBook-Pro:hello-nodejs luminal$
意思上面四行代碼是同步執行的,從頭到尾一行一行依次執行下來。那如果文件"readMe.txt"非常大,那麼這個讀取的時間就會很長,後面要執行的內容只能排隊等待執行,那麼這種情況顯然不合理!
nodejs執行JavaScript的時候它是單線程的,這裏要注意的是:我並沒有說nodejs是單線程的。這種I/O操作,比如說像數據庫連接是很常見的,也是最耗時的。那麼怎麼來解決這個問題呢?這個時候我們可以用到異步,下面我們修改一下代碼如下:
var fs = require('fs');
var readMe = fs.readFile("readMe.txt","utf-8",function(err, data) {
console.log(data);
});
// 延遲5秒執行。我們可以用這個模擬感受下,阻塞的狀態!
//也就是說,有如下耗時的同步操作,那就會阻塞整個線程的運行,
//就算是上面異步的方法,也會被阻塞。當遇見這種情況,這時候你寫nodejs,
//都是要用異步的方法來處理
//var waitTill = new Date(new Date().getTime() + 5 * 1000);
//while (waitTill > new Date()) {}
console.log("finished");
我們來看看輸出結果:
MacBook-Pro:hello-nodejs luminal$ node app
finished
讀我啊 read me
MacBook-Pro:hello-nodejs luminal$
我們會發現 “finished” 先輸出出來了,那麼怎麼回事呢?
readFile是一個異步方法,修改的代碼執行的是異步事件、異步的I/O操作,nodejs執行JavaScript的時候它是單線程的,上面代碼的語句還是一行一行的執行的。那麼 “finished” 爲什麼會先輸出出來?
其實是這樣的,nodejs它維護了一個事件隊列,上面三行語句中,第一句還是會先執行,執行第二句的時候它就在事件隊列當中註冊了一個事件,告訴這個事件隊列,我將要去讀取一個文件。但是裏面的回調函數並沒有被馬上執行,這個操作是瞬間完成的,完成之後它就會執行主線程的第三條語句 console.log("finished");
當主線程空閒的時候,它就會去找事件隊列裏面的事件,把它取出來。在此同時發起一個線程去執行事件隊列裏面的事件,在這裏是讀取一個文件,當讀完成功以後,它再告訴主線程我已經執行成功。
因爲I/O操作它有時候是很耗時的,你不能阻塞別的操作,不能讓別的操作一直在等待它的執行,應該是開啓另一個線程就執行這個I/O操作,它執行成功以後再通知主線程去執行它。
writeFile方法
有readFile方法必然會有與之對應的writeFile方法,下面我們來看看代碼:
var fs = require('fs');
// var readMe = fs.readFile("readMe.txt","utf-8",function(err, data) {
// console.log(data);
// });
var data = "寫寫寫";
fs.writeFile("writeMe.txt", data, function() {
console.log("寫入完畢!");
});
console.log("finished");
我們來看看輸出結果:
MacBook-Pro:hello-nodejs luminal$ node app
finished
寫入完畢!
MacBook-Pro:hello-nodejs luminal$
同樣的,writeFile方法也是異步的方法,所以"finished"先輸出。同時我們會發現,寫入的內容已經寫進去了,如下圖:
可參考的api: