[Node] Node.js path module

前言

每次使用 node.js 建置環境的時候,都會使用到 path 模組,照著教學上的使用都可以正常運行,但是都沒有真正了解它代表的意思。以至於我自己在使用 path 模組的時候常常得不到我要的結果。看看它的官方檔案,研究一下它到底是怎麼使用的。

起手式

基本上,path 模組已經包含在 node.js 的模組裡,不需要另外下載。只需要在使用到的檔案 require 進來就可以。

1
const path  = require('path');

Windows vs POSIX 系統

path 模組的預設行為會因為執行 Node.js 應用的環境不同而不同。在 Windows 和 POSIX 系統下會有些許的不一樣。本篇文章主要是以 POSIX 系統為主。如果是 Windows 的使用者建議可以參考一下官方的 Path | Node.js v9.10.1 文件。

Path 可調用的方法

path.basename(path[, ext])

返回路徑中最後面的部分。

  • ext: optional
1
2
3
4
5
path.basename('/foo/bar/baz/asdf/quux.html');
// Returns: 'quux.html'

path.basename('/foo/bar/baz/asdf/quux.html', '.html');
// Returns: 'quux'

path.delimiter

回傳目前平台的分隔符號。

  • ; for Windows
  • : for POSIX
1
2
3
4
5
console.log(process.env.PATH);
// Prints: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin'

process.env.PATH.split(path.delimiter);
// Returns: ['/usr/bin', '/bin', '/usr/sbin', '/sbin', '/usr/local/bin']

path.dirname(path)

返回路徑中代表資料夾的部分,相似於 Unix 的 dirname 指令。

1
2
path.dirname('/foo/bar/baz/asdf/quux');
// Returns: '/foo/bar/baz/asdf'

path.extname(path)

回傳路徑最後面的部分的 . 後面的副檔名。如果 . 後面為空或沒有 .,又或者最後面部分開頭就是 .,會直接回傳空字串。

用例子來說明會比較清楚:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
path.extname('index.html');
// Returns: '.html'

path.extname('index.coffee.md');
// Returns: '.md'

path.extname('index.');
// Returns: '.'

path.extname('index');
// Returns: ''

path.extname('.index');
// Returns: ''

path.format(pathObject)

回傳以該物件為根據的路徑。和 path.parse() 是完全相反的。

  • object 的屬性包含:
    • dir
    • root
    • base
    • name
    • ext
  • 設定 pathObject 屬性的時候要注意,上列的屬性間依照組合的方式會有不同的優先順序。
    • dirroot 屬性同時存在時, root 會被忽略。
    • base 屬性存在時, nameext 會被忽略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
path.format({
root: '/ignored',
dir: '/home/user/dir',
base: 'file.txt'
});
// Returns: '/home/user/dir/file.txt'

path.format({
root: '/',
base: 'file.txt',
ext: 'ignored'
});
// Returns: '/file.txt'

path.format({
root: '/',
name: 'file',
ext: '.txt'
});
// Returns: '/file.txt'

path.isAbsolute(path)

判斷參數 path 是否為絕對路徑

1
2
3
4
path.isAbsolute('/foo/bar'); // true
path.isAbsolute('/baz/..'); // true
path.isAbsolute('qux/'); // false
path.isAbsolute('.'); // false

path.join([…paths])

用於連接路徑。將所有的 paths 參數以目前系統的 系統分隔符 連接成一個路徑。

* paths 必須是 string 否則會跳錯

1
2
path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// Returns: '/foo/bar/baz/asdf'

path.normalize(path)

將路徑格式化轉換為標準路徑,解析 ...。刪除多餘的 /\

  • 如果其中一個 path 後面有接 ..,則該 path 會被忽略。因為它是沒有意義的。
1
2
3
4
path.normalize('/foo/bar//baz/asdf/quux/..');
// Returns: '/foo/bar/baz/asdf'
path.normalize('/foo/bar//baz/../asdf/quux');
// Returns: '/foo/bar/asdf/quux'

path.parse(path)

將 path 拆成一個物件裡的各個屬性。屬性種類可參考:path.format()

1
2
3
4
5
6
7
path.parse('/home/user/dir/file.txt');
// Returns:
// { root: '/',
// dir: '/home/user/dir',
// base: 'file.txt',
// ext: '.txt',
// name: 'file' }

path.relative(from, to)

此方法帶兩個參數 (from, to),兩個參數都應該是絕對路徑。透過 path.relative 會返回第二個參數相對於第一個參數的相對路徑。

  • 如果兩個參數是一樣的,則會返回一個空字串。
  • 如果其中一個參數為空字串,則執行的檔案目前的路徑則會取代該參數。
1
2
path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb');
// Returns: '../../impl/bbb'

path.resolve([…paths])

解析傳入的 ‘路徑’ 以及 ‘部分路徑’,組合並轉換成一個絕對路徑。

  • 傳入的路徑參數會由右到左被執行。左邊的參數會被叫到右邊的參數前,直到組成一個絕對路徑。
  • 如果所有的參數都已經被執行完,但還是無法產生一個絕對路徑,那就會使用目前的路徑。
  • 最後的絕對路徑會經過格式化成正式的路徑,並且刪除多餘的 /\,除非最後解析出來的路徑是根目錄。
  • 若傳入的參數為空字串,會被忽略。
  • 如果沒有傳入任何參數,會回傳目前的路徑。
1
2
3
4
5
6
7
8
9
path.resolve('/foo/bar', './baz');
// Returns: '/foo/bar/baz'

path.resolve('/foo/bar', '/tmp/file/');
// Returns: '/tmp/file'

path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif');
// if the current working directory is /home/myself/node,
// this returns '/home/myself/node/wwwroot/static_files/gif/image.gif'
  • 其實這樣講還是有點複雜,可以使用下面的方式來思考會比較簡單:
1
2
path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile')
// Return '/tmp/subfile'
$ cd foo/bar
$ cd /tmp/file/
$ cd ..
$ cd a/../subfile

path.spe

會回傳你目前系統中預設的分隔符號。

參考資料