Node.js FS 模組:檔案系統操作基礎

Node.js 的 fs (File System) 模組是與電腦檔案系統互動的核心工具。它讓你能夠像作業系統一樣,進行檔案的讀取、寫入、刪除、重新命名以及權限管理。

核心設計:三種操作模式

fs 模組中,幾乎所有功能都具備三種實作方式。理解它們的差異是寫出高效能程式碼的第一步:

  1. 非同步回呼 (Callback):傳統做法,程式不會被阻塞,執行完後呼叫回呼函式。
  2. 同步阻塞 (Synchronous):函式名帶有 Sync 字尾。會卡住整個主執行緒,直到操作完成。
  3. Promise 模式 (推薦):位於 fs.promises 下,可配合 async/await 使用,兼具效能與可讀性。
金律:在開發 Web 伺服器(如 Express)時,絕不要在請求處理過程中使用同步 (Sync) 版本。這會導致伺服器無法服務同時進來的其他用戶。

讀取檔案 (Reading Files)

如果你不指定編碼,Node.js 預設會回傳原始的 Buffer 資料。

const fs = require('fs');

// 1. 傳統 Callback 寫法
fs.readFile('hello.txt', 'utf8', (err, data) => {
  if (err) return console.error(err);
  console.log('讀取成功:', data);
});

// 2. 現代 Promise 寫法 (最推薦)
const fsPromises = require('fs').promises;
async function read() {
  const data = await fsPromises.readFile('hello.txt', 'utf8');
}

寫入與附加內容 (Writing & Appending)

  • writeFile:會建立新檔案。如果檔案已存在,會直接覆蓋舊內容。
  • appendFile:如果檔案已存在,會在原有的內容後面累加
// 寫入檔案
fs.writeFile('output.txt', '這會覆蓋原檔案', (err) => {
  if (err) throw err;
});

// 附加日誌
const log = `[${new Date().toISOString()}] 系統事件\n`;
fs.appendFile('app.log', log, (err) => {
  if (err) throw err;
});

檔案狀態與存在檢查

在舊版 Node.js 中常用 fs.exists,但現在已被廢棄。正確做法是使用 fs.stat 或檢查讀寫權限的 fs.access

// 獲取檔案詳細資訊
fs.stat('image.jpg', (err, stats) => {
  if (err) return console.log('找不到檔案');

  console.log('檔案大小:', stats.size, '位元組');
  console.log('建立時間:', stats.birthtime);
  console.log('是否為目錄:', stats.isDirectory());
});

常見編碼問題小筆記

在處理文字檔案時,務必明確指定 'utf8' 編碼。如果處理的是圖片、音訊或二進位封包,則省略編碼以獲取 Buffer

  • 文字型讀取fs.readFile(path, 'utf8', ...)
  • 二進位讀取fs.readFile(path, ...) (返回 Buffer)

總結

  1. 除非是單機執行且簡單的 CLI 腳本,否則一律使用非同步版本。
  2. 現代專案建議全面導入 fs.promises
  3. 處理大型檔案(如 100MB 以上)時,請參考 Stream 串流教學 以節省記憶體。