nodejs中的文件系統 簡介 nodejs中的文件系統模塊 Promise版本的fs 文件描述符 fs.stat文件狀態信息 fs的文件讀寫 fs的文件夾操作 path操作

簡介

nodejs使用了異步IO來提升服務端的處理效率。而IO中一個非常重要的方面就是文件IO。今天我們會詳細介紹一下nodejs中的文件系統和IO操作。

nodejs中的文件系統模塊

nodejs中有一個非常重要的模塊叫做fs。這個模塊提供了許多非常實用的函數來訪問文件系統並與文件系統進行交互。

簡單統計一下,fs提供了下面這麼多種使用的文件操作方法:

  • fs.access(): 檢查文件是否存在,以及 Node.js 是否有權限訪問。
  • fs.appendFile(): 追加數據到文件。如果文件不存在,則創建文件。
  • fs.chmod(): 更改文件(通過傳入的文件名指定)的權限。相關方法:fs.lchmod()、fs.fchmod()。
  • fs.chown(): 更改文件(通過傳入的文件名指定)的所有者和羣組。相關方法:fs.fchown()、fs.lchown()。
  • fs.close(): 關閉文件描述符。
  • fs.copyFile(): 拷貝文件。
  • fs.createReadStream(): 創建可讀的文件流。
  • fs.createWriteStream(): 創建可寫的文件流。
  • fs.link(): 新建指向文件的硬鏈接。
  • fs.mkdir(): 新建文件夾。
  • fs.mkdtemp(): 創建臨時目錄。
  • fs.open(): 設置文件模式。
  • fs.readdir(): 讀取目錄的內容。
  • fs.readFile(): 讀取文件的內容。相關方法:fs.read()。
  • fs.readlink(): 讀取符號鏈接的值。
  • fs.realpath(): 將相對的文件路徑指針(.、..)解析爲完整的路徑。
  • fs.rename(): 重命名文件或文件夾。
  • fs.rmdir(): 刪除文件夾。
  • fs.stat(): 返回文件(通過傳入的文件名指定)的狀態。相關方法:fs.fstat()、fs.lstat()。
  • fs.symlink(): 新建文件的符號鏈接。
  • fs.truncate(): 將傳遞的文件名標識的文件截斷爲指定的長度。相關方法:fs.ftruncate()。
  • fs.unlink(): 刪除文件或符號鏈接。
  • fs.unwatchFile(): 停止監視文件上的更改。
  • fs.utimes(): 更改文件(通過傳入的文件名指定)的時間戳。相關方法:fs.futimes()。
  • fs.watchFile(): 開始監視文件上的更改。相關方法:fs.watch()。
  • fs.writeFile(): 將數據寫入文件。相關方法:fs.write()。

注意,上面fs提供的方法都是異步的,所謂異步的意思是,這些方法都提供了回調函數,方便異步觸發相應的處理邏輯。

我們舉一個簡單的讀取文件的例子:

const fs = require('fs')

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

上面的例子中,我們從/tmp文件中讀取了一個flydean.txt文件。並在callback函數中分別對異常和正常的數據進行了處理。

fs在提供異步方法的同時,還提供了同步的方法調用,這個同步的方法就是在異步方法後面加上Sync:

const fs = require('fs')

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

看下將上面的方法改寫成同步方法之後的樣子。

兩者的區別就是,同步方法會阻塞,一直等到file讀取完成。

Promise版本的fs

異步操作怎麼能少得了Promsie, 因爲fs中的操作都是異步的,如果大家不想通過callback來使用fs的話,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('出錯:', error.message);
  }
})('/tmp/flydean.txt');

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

文件描述符

文件描述符就是指在nodejs中,當我們使用fs.open方法獲得的這個返回值。

我們可以通過這個文件描述符來進步和文件進行交互操作。

const fs = require('fs')

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

上面的open方法的第二個參數表示以只讀的方式打開文件。

我們看下常用的文件系統標誌:

  • 'r': 打開文件用於讀取。 如果文件不存在,則會發生異常。

  • 'r+': 打開文件用於讀取和寫入。 如果文件不存在,則會發生異常。

  • 'w': 打開文件用於寫入。 如果文件不存在則創建文件,如果文件存在則截斷文件。

  • 'w+': 打開文件用於讀取和寫入。 如果文件不存在則創建文件,如果文件存在則截斷文件。

  • 'a': 打開文件用於追加。 如果文件不存在,則創建該文件。

  • 'a+': 打開文件用於讀取和追加。 如果文件不存在,則創建該文件。

當然,上面的例子也可以用openSync來改寫:

const fs = require('fs')

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

fs.stat文件狀態信息

nodejs提供了一個fs.Stats類,用來描述文件的狀態信息。

Stats提供了一些非常有用的方法來判斷文件的狀態:

比如:
stats.isDirectory(),stats.isFile(),stats.isSocket(),stats.isSymbolicLink(),stats.ctime等。

stats還提供了一些關於文件時間相關的選項:

  • atime "訪問時間" - 上次訪問文件數據的時間。
  • mtime "修改時間" - 上次修改文件數據的時間。
  • ctime "更改時間" - 上次更改文件狀態(修改索引節點數據)的時間。
  • birthtime "創建時間" - 創建文件的時間。

我們看一下怎麼獲取到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將會作爲fs.stat的回調函數參數傳入。通過fs.Stats,我們再進行一系列的操作。

fs的文件讀寫

上面我們介紹了使用fs進行文件讀取操作,下面我們來介紹怎麼使用fs來進行文件寫入操作:

const fs = require('fs')

const content = 'www.flydean.com'

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

上面是一個callback版本的,我們再看一個同步版本的:

const fs = require('fs')

const content = 'www.flydean.com'

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

writeFile還支持一個額外的options參數,在options參數中,我們可以指定文件寫入的flag標記位,比如:r+,w+,a,a+等等。

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

當然,除了使用a+表示append到文件末尾之外,fs還提供了一個appendFile方法來向文件末尾輸出:

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相對而言負責點,我們舉例說明:

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兩種方式來讀取目錄中的文件。

大家可以看下其中的區別。

path操作

最後,我們介紹一個和file特別相關的path操作,它提供了一些實用工具,用於處理文件和目錄的路徑。

path代表的是路徑。我們通過下面的方式來使用path:

const path = require('path')

爲什麼需要path呢?我們知道這個世界上大約有兩種風格的操作系統,windows和POSIX。

在這兩種操作系統中,路徑的表達方式是不一樣的。所以,我們需要一個通用的path模塊來爲我們解決這個差異。

我們可以通過一個例子來觀察這個差異:

在windows上:

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

在POSIX上:

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

我們先來看一下path.basename這個方法,是用來返回path 的最後一部分。

上面的例子中,我們向windows傳入了一個windows風格的path,所以可以正常解析,得到正常的結果。

而在POSIX環境中,我們傳入了一個windows風格的路徑,無法正常解析,直接返回整個的結果。

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' 從當前目錄開始解析,獲得相對路徑的絕對路徑

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

本文作者:flydean程序那些事

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

本文來源:flydean的博客

歡迎關注我的公衆號:「程序那些事」最通俗的解讀,最深刻的乾貨,最簡潔的教程,衆多你不知道的小技巧等你來發現!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章