書(shū)上細(xì)節(jié)回顧
<p>之前在看《一本全面的Node.js教程》在書(shū)中最后的部分盗迟,作者實(shí)現(xiàn)了圖片上傳并在另外一個(gè)頁(yè)面中顯示的功能点楼。對(duì)圖片進(jìn)行保存是通過(guò)對(duì)請(qǐng)求的form表單進(jìn)行解析突倍,如下:
<p>這里使用了fs模塊的一個(gè)renameSync的方法钩杰,顧名思義谨设,這個(gè)方法首先是將目標(biāo)文件重命名低散,目標(biāo)文件的路徑由回調(diào)函數(shù)的參數(shù)傳入俯邓。這樣就可以將文件保存到自己定義的目錄下。但是這里rename后面還加了一個(gè)Sync熔号』蓿回想node.js之前接觸到的大量的異步知識(shí),于是思考fs模塊中應(yīng)該如何使用同步與異步引镊,以及其他基本的文件操作朦蕴。
fs模塊介紹
<p>打開(kāi)node.js的官方文檔篮条,對(duì)fs的介紹一目了然:fs模塊是文件操作的封裝,它提供了文件讀取梦重、寫(xiě)入兑燥、更名、刪除琴拧、遍歷目錄降瞳、鏈接等POSIX文件系統(tǒng)操作。與其它模塊不同的是蚓胸,fs模塊中所有的操作都提供了異步的和同步的兩個(gè)版本挣饥。
<p>其中,異步的方法的最后一個(gè)參數(shù)往往是完成以后的回調(diào)函數(shù)沛膳,而這個(gè)回調(diào)函數(shù)的第一個(gè)參數(shù)往往是err扔枫。如果操作成功完成,那么這個(gè)參數(shù)將會(huì)是null或者undefined锹安。當(dāng)對(duì)文件的操作是一系列有順序的操作時(shí)短荐,應(yīng)該使用回調(diào)嵌套√究蓿或者使用同步的版本忍宋。
<p>下面從最簡(jiǎn)單的讀寫(xiě)開(kāi)始介紹。
讀:
<p>fs.readFile 是讀取整個(gè)文件的異步方法风罩。注意:只要后面沒(méi)有加Sync糠排,默認(rèn)為異步。fs.readFile(filename,[encoding],[callback(error,data)]是最簡(jiǎn)單的文件讀取函數(shù)超升,它接受一個(gè)必選參數(shù)filename入宦,表示讀取的文件名,第二個(gè)參數(shù)encoding是可選的室琢,表示文件字符編碼乾闰。callback是回調(diào)函數(shù),用于接收文件的內(nèi)容研乒。如果不指定encoding汹忠,則callback就是第二個(gè)參數(shù)”荆回調(diào)函數(shù)提供兩個(gè)參數(shù)err和data宽菜,err表示有沒(méi)有錯(cuò)誤發(fā)生,data是文件內(nèi)容竿报。如果指定encoding铅乡,data是一個(gè)解析后的字符串,否則將會(huì)以Buffer形式表示的二進(jìn)制數(shù)據(jù)烈菌。
寫(xiě):
<p>結(jié)果:
<p>讀寫(xiě)成功阵幸。接下來(lái)介紹append:
<p>其實(shí)writeFile也可以實(shí)現(xiàn)append的功能花履,只要置flag為a即可。這里總結(jié)一下flag的值的含義:
- r:以讀取模式打開(kāi)文件
- r+:以讀寫(xiě)模式
- w:以寫(xiě)入模式打開(kāi)挚赊,如果不存在則創(chuàng)建
- w+:以讀寫(xiě)模式打開(kāi)诡壁,如果不存在則創(chuàng)建
- a:以追加模式打開(kāi)文件,如果不存在則創(chuàng)建
- a+:以讀取追加模式打開(kāi)文件荠割,如果文件不存在則創(chuàng)建妹卿。
<p>結(jié)果:
<p>至此,fs最常用的文件讀寫(xiě)方法已經(jīng)介紹完畢蔑鹦。
其他fs模塊的方法:
fs.open:
<p>fs.opne(path,flags,[mode],[callback(err,fd)])是POSIX open函數(shù)的封裝夺克,與c語(yǔ)言標(biāo)準(zhǔn)庫(kù)中的fopen函數(shù)類似。它接受兩個(gè)必選參數(shù)嚎朽,path為文件的路徑铺纽。fd是讀取文件的文件描述符。
fs.read:
<p>fs.read(fd,buffer,offset,length,position,[callback(err,bytesRead,buffer)])是POSIX read函數(shù)的封裝哟忍,相比f(wàn)s.readFile提供了更底層的接口狡门。fs.read的功能是從指定的文件描述符fd中讀取數(shù)據(jù)并寫(xiě)入buffer指向的緩沖區(qū)對(duì)象。offset是buffer的寫(xiě)入偏移量锅很。length是要從文件中讀取的字節(jié)數(shù)融撞。position是文件讀取的起始位置,如果position的值為null粗蔚,則會(huì)從當(dāng)前文件指針的位置讀取,回調(diào)函數(shù)傳遞bytesRead和buffer饶火,分別表示讀取的字節(jié)數(shù)和緩沖區(qū)對(duì)象鹏控。
- fs.mkdir fs.mkdir(path,[mode],callback),創(chuàng)建目錄。
- fs.readdir fs.readdir(path,callback),讀取目錄肤寝,callback(err, files)当辐,files數(shù)組傳回的是讀取的目錄下所有文件的文件名稱。
- fs.rename fs.rename(oldPath, newPath, callback),重命名(移動(dòng))文件鲤看。
- fs.exists fs.exists(path,callback),查看文件與目錄是否存在
- fs.stat fs.stat(path, callback)查看文件信息缘揪。
同步異步比較:
<p>首先編寫(xiě)同步讀取兩個(gè)較大的文件的程序:
結(jié)果:
很明顯,是同步完成的义桂。
再來(lái)看看異步的程序:
異步讀取的結(jié)果:
<p>奇怪的事情發(fā)生了找筝,程序先執(zhí)行完了,耗時(shí)36毫秒慷吊。第二個(gè)文件較小袖裕,先讀完,僅花了145毫秒溉瓶,第一個(gè)文件較大急鳄,讀完一共花了345毫秒谤民。但是總體上比同步讀取速度快。
注意
<p>異步IO操作在進(jìn)行大量的IO操作時(shí)可以有效節(jié)省系統(tǒng)時(shí)間疾宏,但是需要注意操作順序的問(wèn)題张足。下面看一個(gè)例子,在例子中坎藐,我們想先修改文件名稱为牍,再讀取文件。同步:
結(jié)果:
如果異步程序不加任何限制顺饮,會(huì)出錯(cuò):
結(jié)果:
因此在進(jìn)行有順序的一系列操作的時(shí)候應(yīng)該采用異步回調(diào)嵌套如下吵聪,或者干脆采用同步的方法。這也是同步方法的優(yōu)點(diǎn)和存在的意義兼雄。