Node.js精進(6)——文件

  文件系統是一種用於向用戶提供底層數據訪問的機制,同時也是一套實現了數據的存儲、分級組織、訪問和獲取等操作的抽象數據類型。

  Node.js 中的fs模塊就是對文件系統的封裝,整合了一套標準 POSIX 文件 I/O 操作的集合,包括文件的讀寫、刪除、遍歷、重命名等操作。

  fs 模塊中的所有方法都提供了三種形式:回調、同步和 Promise ,其中 Promise 是在 Node.js 的版本 10 中引入的。

  本系列所有的示例源碼都已上傳至Github,點擊此處獲取。 

一、三種形式

  在回調形式的方法中,最後一個參數是其回調函數,會異步地調用,其中回調函數的第一個參數始終爲異常預留,不過有個例外是 exists() 方法。

  回調形式不容易書寫,很容易就會形成回調地獄。

  雖然同步形式的方法比較容易書寫,但是在執行時會阻止 Node.js 事件循環和阻塞 JavaScript 執行,直到操作完成。

  Promise 形式的方法會使用底層的 Node.js 線程池,在事件循環線程之外異步地執行文件系統操作。對同一文件執行多個併發修改時必須小心,有可能會損壞數據。

  以讀取文件爲例,三種形式的寫法如下所示,若不指定編碼,那麼輸出的將是 Buffer 實例。

const fs = require('fs');
// 回調
fs.readFile('./data.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data);    // strick
});

// 同步
const data = fs.readFileSync('./data.txt', 'utf8');
console.log(data);    // strick

// Promise
const { promises } = fs;
async function readFilePromise() {
  const data = await promises.readFile('./data.txt', 'utf8');
  console.log(data);    // strick
}
readFilePromise();

二、基礎使用

1)判斷文件是否存在

  exists() 方法可用於判斷文件是否存在,但在上一小節中曾提到,它已被棄用。

  這是因爲此回調的參數與其他回調不一致。通常,Node.js 回調的第一個參數是 err 參數,然後跟可選的其他參數,但 fs.exists() 回調只有一個布爾參數,如下所示。

fs.exists('./data.txt', isExist => {
  console.log(isExist);
});

  再則是因爲 exists() 方法的功能用 access() 方法也能實現,其內部源碼如下所示,其實也是調用了 access() 方法。

function exists(path, callback) {
  maybeCallback(callback);
  // 構造回調函數
  function suppressedCallback(err) {
    callback(err ? false : true);
  }
  try {
    fs.access(path, F_OK, suppressedCallback);
  } catch {
    return callback(false);
  }
}

  其中 F_OK 是 fs 模塊中的一個常量,表示文件是否存在,使用方法如下所示,R_OK 表示是否可讀,W_OK 表示是否可寫。

const { constants } = require('fs');
const {  F_OK,  R_OK,  W_OK } = constants;

  注意,在調用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,不能使用 fs.access() 檢查文件是否存在。

  因爲這樣做會引入競爭條件,其他進程可能會在兩次調用之間修改文件狀態,造成非預期的結果。

  遇到這種場景,推薦的做法是直接打開、讀取或寫入文件,當文件不可用時再做處理。

  另一種判斷文件是否存在的方法是調用 stat(),讀取文件屬性。

  它有兩個方法 isDirectory() 和 isFile() 可分別判斷是否是目錄和是否是文件,如下所示。

fs.stat('./data.txt', (err, stats) => {
  console.log(stats.isDirectory());
  console.log(stats.isFile());
});

  同樣要注意的是,它也不能在調用 fs.open()、fs.readFile() 或 fs.writeFile() 之前,檢查文件是否存在。

2)方法

  下面羅列的是 fs 模塊的一些方法。

  • fs.open():打開文件,可設置文件模式。
  • fs.close():關閉文件描述符。
  • fs.createReadStream():創建可讀的文件流。
  • fs.createWriteStream():創建可寫的文件流。
  • fs.readFile():讀取文件的內容,相關方法:fs.read()。
  • fs.writeFile():寫入文件,相關方法:fs.write()。
  • fs.link():新建指向文件的硬鏈接。
  • fs.unlink():刪除文件或符號鏈接。
  • fs.mkdir():新建文件夾。
  • fs.rmdir():刪除文件夾。
  • fs.readdir():讀取目錄的內容。
  • fs.stat():讀取文件屬性,相關方法:fs.fstat()、fs.lstat()。
  • fs.access():檢查文件是否存在,以及 Node.js 是否有權限訪問。
  • fs.rename():重命名文件或文件夾。
  • fs.appendFile():追加數據到文件,如果文件不存在,則創建文件。
  • fs.copyFile():拷貝文件,可覆蓋文件內容。
  • fs.chmod():更改文件(通過傳入的文件名指定)的權限,相關方法:fs.lchmod()、fs.fchmod()。
  • fs.chown():更改文件(通過傳入的文件名指定)的所有者和羣組,相關方法:fs.fchown()、fs.lchown()。
  • fs.watchFile():開始監控文件的更改,相關方法:fs.watch()。
  • fs.unwatchFile():停止監控文件的更改。

3)路徑

  路徑處理並不是在 fs 模塊,而是在path模塊,它的方法包括。

  • path.basename():讀取路徑的最後一部分。
  • path.dirname():讀取路徑的目錄部分。
  • path.extname():讀取路徑的文件擴展名。
  • path.isAbsolute():判斷是否是絕對路徑。
  • path.join():將多個部分合併成一個完整的路徑。
  • path.normalize():當包含類似 .、.. 或 // 等相對的說明符時,就嘗試計算實際的路徑。
  • path.parse():解析成路徑對象。
  • path.relative():基於當前目錄,返回從第一個路徑到第二個路徑的相對路徑。
  • path.resolve():將相對路徑計算成絕對路徑。
path.basename('../06/data.txt')    // data.txt
path.dirname('../06/data.txt');    // ../06
path.extname('../06/data.txt');    // .txt
path.isAbsolute('../06/data.txt');     // false
path.join('../', '06', 'data.txt');    // ../06/data.txt
path.normalize('/../06/data.txt');     // /06/data.txt
// { root: '', dir: '../06', base: 'data.txt', ext: '.txt', name: 'data' }
path.parse('../06/data.txt');
path.relative('../', '../06/data.txt');    // 06/data.txt
path.resolve('../06/data.txt');        // /Users/code/web/node/06/data.txt

 

參考資料:

判斷文件存在

深入Node.js源碼之文件系統

Node.js官網文檔 API文件系統

餓了麼File

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