nodejs中的文件系統(tǒng)

簡(jiǎn)介

nodejs使用了異步IO來(lái)提升服務(wù)端的處理效率桅咆。而IO中一個(gè)非常重要的方面就是文件IO螟深。今天我們會(huì)詳細(xì)介紹一下nodejs中的文件系統(tǒng)和IO操作赠尾。

nodejs中的文件系統(tǒng)模塊

nodejs中有一個(gè)非常重要的模塊叫做fs毡证。這個(gè)模塊提供了許多非常實(shí)用的函數(shù)來(lái)訪問(wèn)文件系統(tǒng)并與文件系統(tǒng)進(jìn)行交互转砖。

簡(jiǎn)單統(tǒng)計(jì)一下赔癌,fs提供了下面這么多種使用的文件操作方法:

  • fs.access(): 檢查文件是否存在诞外,以及 Node.js 是否有權(quán)限訪問(wèn)。
  • fs.appendFile(): 追加數(shù)據(jù)到文件灾票。如果文件不存在峡谊,則創(chuàng)建文件。
  • fs.chmod(): 更改文件(通過(guò)傳入的文件名指定)的權(quán)限刊苍。相關(guān)方法:fs.lchmod()既们、fs.fchmod()。
  • fs.chown(): 更改文件(通過(guò)傳入的文件名指定)的所有者和群組正什。相關(guān)方法:fs.fchown()啥纸、fs.lchown()。
  • fs.close(): 關(guān)閉文件描述符婴氮。
  • fs.copyFile(): 拷貝文件斯棒。
  • fs.createReadStream(): 創(chuàng)建可讀的文件流。
  • fs.createWriteStream(): 創(chuàng)建可寫(xiě)的文件流主经。
  • fs.link(): 新建指向文件的硬鏈接荣暮。
  • fs.mkdir(): 新建文件夾。
  • fs.mkdtemp(): 創(chuàng)建臨時(shí)目錄罩驻。
  • fs.open(): 設(shè)置文件模式穗酥。
  • fs.readdir(): 讀取目錄的內(nèi)容。
  • fs.readFile(): 讀取文件的內(nèi)容鉴腻。相關(guān)方法:fs.read()迷扇。
  • fs.readlink(): 讀取符號(hào)鏈接的值。
  • fs.realpath(): 將相對(duì)的文件路徑指針(.爽哎、..)解析為完整的路徑蜓席。
  • fs.rename(): 重命名文件或文件夾。
  • fs.rmdir(): 刪除文件夾课锌。
  • fs.stat(): 返回文件(通過(guò)傳入的文件名指定)的狀態(tài)厨内。相關(guān)方法:fs.fstat()祈秕、fs.lstat()。
  • fs.symlink(): 新建文件的符號(hào)鏈接雏胃。
  • fs.truncate(): 將傳遞的文件名標(biāo)識(shí)的文件截?cái)酁橹付ǖ拈L(zhǎng)度请毛。相關(guān)方法:fs.ftruncate()。
  • fs.unlink(): 刪除文件或符號(hào)鏈接瞭亮。
  • fs.unwatchFile(): 停止監(jiān)視文件上的更改方仿。
  • fs.utimes(): 更改文件(通過(guò)傳入的文件名指定)的時(shí)間戳。相關(guān)方法:fs.futimes()统翩。
  • fs.watchFile(): 開(kāi)始監(jiān)視文件上的更改仙蚜。相關(guān)方法:fs.watch()。
  • fs.writeFile(): 將數(shù)據(jù)寫(xiě)入文件厂汗。相關(guān)方法:fs.write()委粉。

注意,上面fs提供的方法都是異步的娶桦,所謂異步的意思是贾节,這些方法都提供了回調(diào)函數(shù),方便異步觸發(fā)相應(yīng)的處理邏輯衷畦。

我們舉一個(gè)簡(jiǎn)單的讀取文件的例子:

const fs = require('fs')

fs.readFile('/tmp/flydean.txt', 'utf8' , (err, data) => {
  if (err) {
    console.error(err)
    return
  }
  console.log(data)
})

上面的例子中栗涂,我們從/tmp文件中讀取了一個(gè)flydean.txt文件。并在callback函數(shù)中分別對(duì)異常和正常的數(shù)據(jù)進(jìn)行了處理祈争。

fs在提供異步方法的同時(shí)戴差,還提供了同步的方法調(diào)用,這個(gè)同步的方法就是在異步方法后面加上Sync:

const fs = require('fs')

try {
  const data = fs.readFileSync('/tmp/flydean.txt', 'utf8')
  console.log(data)
} catch (err) {
  console.error(err)
}

看下將上面的方法改寫(xiě)成同步方法之后的樣子铛嘱。

兩者的區(qū)別就是,同步方法會(huì)阻塞袭厂,一直等到file讀取完成墨吓。

Promise版本的fs

異步操作怎么能少得了Promsie, 因?yàn)閒s中的操作都是異步的,如果大家不想通過(guò)callback來(lái)使用fs的話(huà)纹磺,fs也提供了Promise版本帖烘。

還是剛剛的readfile的例子,我們看看如果使用Promise該怎么處理:

const fs = require('fs/promises');

(async function(path) {
  try {
    await fs.readFile(path, 'utf8' );
    console.log(`讀取文件成功 ${path}`);
  } catch (error) {
    console.error('出錯(cuò):', error.message);
  }
})('/tmp/flydean.txt');

fs的promise版本在fs/promises下面橄杨,上面的例子中我們使用了async和await秘症,以同步的方式編寫(xiě)異步程序,非常的方便式矫。

文件描述符

文件描述符就是指在nodejs中乡摹,當(dāng)我們使用fs.open方法獲得的這個(gè)返回值。

我們可以通過(guò)這個(gè)文件描述符來(lái)進(jìn)步和文件進(jìn)行交互操作采转。

const fs = require('fs')

fs.open('/tmp/flydean.txt', 'r', (err, fd) => {
  //fd 是文件描述符聪廉。
})

上面的open方法的第二個(gè)參數(shù)表示以只讀的方式打開(kāi)文件瞬痘。

我們看下常用的文件系統(tǒng)標(biāo)志:

  • 'r': 打開(kāi)文件用于讀取。 如果文件不存在板熊,則會(huì)發(fā)生異常框全。

  • 'r+': 打開(kāi)文件用于讀取和寫(xiě)入。 如果文件不存在干签,則會(huì)發(fā)生異常津辩。

  • 'w': 打開(kāi)文件用于寫(xiě)入。 如果文件不存在則創(chuàng)建文件容劳,如果文件存在則截?cái)辔募?/p>

  • 'w+': 打開(kāi)文件用于讀取和寫(xiě)入喘沿。 如果文件不存在則創(chuàng)建文件,如果文件存在則截?cái)辔募?/p>

  • 'a': 打開(kāi)文件用于追加鸭蛙。 如果文件不存在摹恨,則創(chuàng)建該文件。

  • 'a+': 打開(kāi)文件用于讀取和追加娶视。 如果文件不存在晒哄,則創(chuàng)建該文件。

當(dāng)然肪获,上面的例子也可以用openSync來(lái)改寫(xiě):

const fs = require('fs')

try {
  const fd = fs.openSync('/tmp/flydean.txt', 'r')
} catch (err) {
  console.error(err)
}

fs.stat文件狀態(tài)信息

nodejs提供了一個(gè)fs.Stats類(lèi)寝凌,用來(lái)描述文件的狀態(tài)信息。

Stats提供了一些非常有用的方法來(lái)判斷文件的狀態(tài):

比如:
stats.isDirectory()孝赫,stats.isFile()较木,stats.isSocket(),stats.isSymbolicLink()青柄,stats.ctime等伐债。

stats還提供了一些關(guān)于文件時(shí)間相關(guān)的選項(xiàng):

  • atime "訪問(wèn)時(shí)間" - 上次訪問(wèn)文件數(shù)據(jù)的時(shí)間。
  • mtime "修改時(shí)間" - 上次修改文件數(shù)據(jù)的時(shí)間致开。
  • ctime "更改時(shí)間" - 上次更改文件狀態(tài)(修改索引節(jié)點(diǎn)數(shù)據(jù))的時(shí)間峰锁。
  • birthtime "創(chuàng)建時(shí)間" - 創(chuàng)建文件的時(shí)間。

我們看一下怎么獲取到fs.stat:

const fs = require('fs')
fs.stat('/tmp/flydean.txt', (err, stats) => {
  if (err) {
    console.error(err)
    return
  }

  stats.isFile() //true
  stats.isDirectory() //false
  stats.isSymbolicLink() //false
  stats.size //文件大小
})

fs.Stats將會(huì)作為fs.stat的回調(diào)函數(shù)參數(shù)傳入双戳。通過(guò)fs.Stats虹蒋,我們?cè)龠M(jìn)行一系列的操作。

fs的文件讀寫(xiě)

上面我們介紹了使用fs進(jìn)行文件讀取操作飒货,下面我們來(lái)介紹怎么使用fs來(lái)進(jìn)行文件寫(xiě)入操作:

const fs = require('fs')

const content = 'www.flydean.com'

fs.writeFile('/tmp/flydean.txt', content, err => {
  if (err) {
    console.error(err)
    return
  }
  //文件寫(xiě)入成功魄衅。
})

上面是一個(gè)callback版本的,我們?cè)倏匆粋€(gè)同步版本的:

const fs = require('fs')

const content = 'www.flydean.com'

try {
  const data = fs.writeFileSync('/tmp/flydean.txt', content)
  //文件寫(xiě)入成功塘辅。
} catch (err) {
  console.error(err)
}

writeFile還支持一個(gè)額外的options參數(shù)晃虫,在options參數(shù)中,我們可以指定文件寫(xiě)入的flag標(biāo)記位莫辨,比如:r+傲茄,w+毅访,a,a+等等盘榨。

fs.writeFile('/tmp/flydean.txt', content, { flag: 'a+' }, err => {})

當(dāng)然喻粹,除了使用a+表示append到文件末尾之外,fs還提供了一個(gè)appendFile方法來(lái)向文件末尾輸出:

const fs = require('fs')

const content = 'www.flydean.com'

fs.appendFile('/tmp/flydean.txt', content, err => {
  if (err) {
    console.error(err)
    return
  }
  //文件append成功草巡。
})

fs的文件夾操作

有文件就有文件夾守呜,fs提供了一系列的文件夾操作,比如:

mkdir山憨,readdir查乒,rename rmdir操作。

readdir相對(duì)而言負(fù)責(zé)點(diǎn)郁竟,我們舉例說(shuō)明:

const fs = require('fs')
const folderPath = '/tmp'

fs.readdir(folderPath, function(err,files){
    if(err){
        console.log(err);
    }
    files.map(file => console.log(file));
})

fs.readdirSync(folderPath).map(fileName => {
    console.log(fileName);
})

上面的例子中玛迄,我們分別使用了readdir和readdirSync兩種方式來(lái)讀取目錄中的文件。

大家可以看下其中的區(qū)別棚亩。

path操作

最后蓖议,我們介紹一個(gè)和file特別相關(guān)的path操作,它提供了一些實(shí)用工具讥蟆,用于處理文件和目錄的路徑勒虾。

path代表的是路徑。我們通過(guò)下面的方式來(lái)使用path:

const path = require('path')

為什么需要path呢瘸彤?我們知道這個(gè)世界上大約有兩種風(fēng)格的操作系統(tǒng)修然,windows和POSIX。

在這兩種操作系統(tǒng)中质况,路徑的表達(dá)方式是不一樣的愕宋。所以,我們需要一個(gè)通用的path模塊來(lái)為我們解決這個(gè)差異结榄。

我們可以通過(guò)一個(gè)例子來(lái)觀察這個(gè)差異:

在windows上:

path.basename('C:\\temp\\myfile.html');
// 返回: 'myfile.html'

在POSIX上:

path.basename('C:\\temp\\myfile.html');
// 返回: 'C:\\temp\\myfile.html'

我們先來(lái)看一下path.basename這個(gè)方法掏婶,是用來(lái)返回path 的最后一部分。

上面的例子中潭陪,我們向windows傳入了一個(gè)windows風(fēng)格的path,所以可以正常解析最蕾,得到正常的結(jié)果依溯。

而在POSIX環(huán)境中,我們傳入了一個(gè)windows風(fēng)格的路徑瘟则,無(wú)法正常解析黎炉,直接返回整個(gè)的結(jié)果。

path還有很多非常有用的方法醋拧,比如:

const notes = '/tmp/notes.txt'

path.dirname(notes) // /tmp
path.basename(notes) // notes.txt
path.extname(notes) // .txt

path.join('/', 'tmp', 'notes.txt') //'/tmp/notes.txt'

path.resolve('notes.txt') //'/Users/flydean/notes.txt' 從當(dāng)前目錄開(kāi)始解析慷嗜,獲得相對(duì)路徑的絕對(duì)路徑

path.normalize('/tmp/flydean..//test.txt') ///tmp/test.txt  嘗試計(jì)算實(shí)際的路徑

本文作者:flydean程序那些事

本文鏈接:http://www.flydean.com/nodejs-file-system/

本文來(lái)源:flydean的博客

歡迎關(guān)注我的公眾號(hào):「程序那些事」最通俗的解讀淀弹,最深刻的干貨,最簡(jiǎn)潔的教程庆械,眾多你不知道的小技巧等你來(lái)發(fā)現(xiàn)薇溃!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缭乘,隨后出現(xiàn)的幾起案子沐序,更是在濱河造成了極大的恐慌,老刑警劉巖堕绩,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件策幼,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡奴紧,警方通過(guò)查閱死者的電腦和手機(jī)特姐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)黍氮,“玉大人唐含,你說(shuō)我怎么就攤上這事÷饲” “怎么了觉壶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)件缸。 經(jīng)常有香客問(wèn)我铜靶,道長(zhǎng),這世上最難降的妖魔是什么他炊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任争剿,我火速辦了婚禮,結(jié)果婚禮上痊末,老公的妹妹穿的比我還像新娘蚕苇。我一直安慰自己,他們只是感情好凿叠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布涩笤。 她就那樣靜靜地躺著,像睡著了一般盒件。 火紅的嫁衣襯著肌膚如雪蹬碧。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天炒刁,我揣著相機(jī)與錄音恩沽,去河邊找鬼。 笑死翔始,一個(gè)胖子當(dāng)著我的面吹牛罗心,可吹牛的內(nèi)容都是我干的里伯。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼渤闷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼疾瓮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起肤晓,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤爷贫,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后补憾,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體漫萄,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年盈匾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腾务。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡削饵,死狀恐怖岩瘦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窿撬,我是刑警寧澤启昧,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站劈伴,受9級(jí)特大地震影響密末,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜跛璧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一严里、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧追城,春花似錦刹碾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至色洞,卻和暖如春坊萝,著一層夾襖步出監(jiān)牢的瞬間瞳脓,已是汗流浹背泳桦。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工盗迟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涵叮,地道東北人惭蹂。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓伞插,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盾碗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子媚污,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容