昨天學習 Node.js 的模組系統,今天要進入另一個開發中常使用的好朋友:Path 模組。
它的角色就像「地圖專家」,幫我們正確處理檔案路徑,
無論你在 Windows、macOS、Linux,寫出來的程式都能順利運作。
path
?如果直接用字串拼路徑,常常會踩坑:
\
,Linux/Mac 用 /
。./
、../
稍不注意就會找錯地方。👉 這些問題交給 path
,都能輕鬆解決。
project/
├── index.js
├── notes.txt
├── images/
│ └── logo.png
└── data/
└── users.json
以下範例假設在 project/index.js
執行:
import path from "node:path";
const filePath = path.join("project", "data", "users.json");
console.log("完整路徑:", filePath);
console.log("檔名:", path.basename(filePath));
console.log("副檔名:", path.extname(filePath));
console.log("所在目錄:", path.dirname(filePath));
輸出:
完整路徑: project/data/users.json
檔名: users.json
副檔名: .json
所在目錄: project/data
path.join(...segments)
→ 安全拼接路徑(會自動處理 /
或 \
)。path.resolve(...segments)
→ 一定會回傳絕對路徑。path.basename(p)
→ 取檔名(含副檔名)。path.extname(p)
→ 取副檔名。path.dirname(p)
→ 取目錄名稱。path.parse(p)
→ 把路徑拆成物件(root、dir、name、ext…)。path.format(obj)
→ 把物件重新組合成路徑。path.join()
與 path.**resolve**()
的差異path.join()
..
、.
)。path.join('project', 'data', 'users.json');
// → 'project/data/users.json'
path.join('/foo', '/bar', 'baz');
// → '/bar/baz'
path.resolve()
path.resolve('project', 'data', 'users.json');
// → /Users/you/current-dir/project/data/users.json
path.resolve('/foo', 'bar', 'baz');
// → /foo/bar/baz
path.parse()
與 path.format()
path.parse(p)
把路徑拆解成物件:
const info = path.parse('/Users/you/project/data/users.json');
console.log(info);
結果:
{
"root": "/",
"dir": "/Users/you/project/data",
"base": "users.json",
"ext": ".json",
"name": "users"
}
path.format(obj)
把物件組回路徑:
const newPath = path.format({
dir: '/Users/you/project/data',
name: 'users.v2',
ext: '.json'
});
console.log(newPath);
// → /Users/you/project/data/users.v2.json
C:\Users\you\project\data\users.json
/Users/you/project/data/users.json
./data/users.json
../images/logo.png
很多人會這樣寫:
import fs from "node:fs";
fs.readFile("./data/file.txt", "utf-8", (err, data) => {
if (err) throw err;
console.log(data);
});
這裡的 ./data/file.txt
不是程式檔案所在的資料夾,而是「程式執行時的工作目錄 (process.cwd()
)」。
./
vs __dirname
vs process.cwd()
比較表名稱 | 代表什麼? | 特點 | 什麼時候用? |
---|---|---|---|
./ |
執行時的相對路徑 | 相對於「在哪個資料夾執行 node 指令」 |
不穩定,容易出錯 |
__dirname |
程式檔案所在的資料夾 | 與程式碼位置綁定,不受執行位置影響 | ✅ 推薦用於讀寫檔案 |
process.cwd() |
程式執行時的工作目錄 | 與 ./ 等價,可用來檢查當前目錄 |
CLI 工具、專案根目錄 |
專案結構:
project/
├── index.js
└── data/
└── file.txt
情境一(在 project/
內執行):
cd project
node index.js # ✅ 可以找到 data/file.txt
情境二(在上一層執行):
cd ..
node project/index.js # ❌ 找不到 data/file.txt
因為此時 ./
指的是「上一層資料夾」,不是 project
。
__dirname
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const filePath = path.resolve(__dirname, "data", "file.txt");
fs.readFile(filePath, "utf-8", (err, data) => {
if (err) throw err;
console.log(data);
});
這樣不管你在哪個資料夾執行,都能正確找到 data/file.txt
。
今天我們學到:
join
vs resolve
→ 前者拼接路徑,後者算絕對路徑。
basename
、extname
、dirname
→ 快速取檔名、附檔名與目錄。
parse
與 format
→ 路徑物件與字串互轉。
⚠️ 陷阱:相對路徑依賴「執行位置」,不是檔案位置。
→ 解法:搭配 __dirname
+ path.resolve()
。