node:path
超级常用的一个模块,例如在开发 nodejs 命令行工具的时候, 处理路径的时候,需要用到这个模块
口径
路径的不同部分有不同的叫法,首先需要知道各部分叫什么,便于我们在代码中命名
对于路径 /a/b/c/d/index.html,我们称:
dirname=>/a/b/c/dbasename=>index.htmlextname=>.html
如表所示:
/ | home/user/dir/ | file | .txt |
| root | name | ext | |
| dir | base | ||
join/resolve
两个方法都用于拼接路径,但是略有不同
join方法在于抹除/的影响,例如下面的例子,不关心传入的路径中,前后是否有/,拼接的时候,会自动抹去和添加/,使之成为合法的路径
import { join } from 'node:path'
console.log(
join('/a/', 'b', '/c'), // => /a/b/c
join('/a/', '/b', '/c') // => /a/b/c
join('/a', '/b', '/c') // => /a/b/c
join('a', '/b', '/c') // => a/b/c
)- 而
resolve会从当前目录(cwd)开始计算,而且默认情况下是返回绝对路径
import { resolve } from 'node:path'
console.log(
resolve('a', 'b', 'c'),
// => /Users/peterroe/project/a/b/c
resolve('./a', 'b', 'c')
// => /Users/peterroe/project/a/b/c
)而且更像是在执行 shell 中 cd 命令,这意味着参数中如果存在像 /a 这样的绝对路径,则会返回到根目录:
resolve('a', 'b/c'), //=> /Users/peterroe/project/a/b/c
resolve('a', '/b/c') //=> /b/c
resolve('a', 'b','../c') //=> a/cbasename
返回路径最后的名称,第二个参数可以传入要删除的可选后缀
import { basename } from 'node:path'
basename('/a/b/c/d/demo'), //=> demo
basename('/a/b/c/d/demo/'), //=> demo
basename('/a/b/c/d/demo.html'), //=> demo.html
basename('/a/b/c/d/demo.html', '.html'), //=> demo
basename('/a/b/c/d/demo.html', '.css'), //=> demo.htmldirname
返回路径的目录名
import { dirname } from 'node:path'
dirname('/a/b/c/d/demo'), //=> /a/b/c/d
dirname('/a/b/c/d/demo/'), //=> /a/b/c/d
dirname('/a/b/c/d/demo.html'), //=> /a/b/c/dextname
返回路径或者文件的后缀名,只取最后一个
import { extname } from 'node:path'
extname('/a/b/c/d/demo'), //=> ''
extname('/a/b/c/d/demo/'), //=> ''
extname('/a/b/c/d/demo.html'), //=> '.html'
extname('/a/b/c/d/demo.map.js'), //=> '.js'
extname('index.html'), //=> '.html'
extname('.d.ts'), //=> '.ts'是否是绝对路径
import { isAbsolute } from 'node:path'
isAbsolute('/foo/bar'), // true
isAbsolute('/baz/..'), // true
isAbsolute('qux/'), // false
isAbsolute('.'), // falsenormalize
上面我们提到 resolve 方法可以像执行 cd 命令一样生成我们的路径,但是遗憾的是 resolve 的返回值是基于当前文件系统的绝对路径的,有时间不想要这种和本地文件系统有关的结果
这个时候可以使用 normalize,但是只能传入一个参数
import { resolve, normalize, join } from 'node:path'
const pathOne = 'a'
const pathTwo = 'b'
const pathThree = '../c'
resolve(pathOne, pathTwo, pathThree), //=> /path/to/project/a/c
// 即保存绝对路径,又和本地文件系统无关
normalize([pathOne, pathTwo, pathThree].join('/')), //=> /a/c
join(pathOne, pathTwo, pathThree), //=> a/c
// 当然,更多的情况是处理本身就是一个错乱的路径
normalize('/foo/bar//baz/asdf/quux/..') //=> /foo/bar/baz/asdfparse
解析文件路径
parse('/home/user/dir/file.txt')
/*
{
root: '/',
dir: '/home/user/dir',
base: 'file.txt',
ext: '.txt',
name: 'file'
}
*/format
有 parse 通常就会有 format,可以传入几个参数,有不同的优先级,详细点击这里
relative
如果说 resolve(A, B) = C,那么 relative 就像 relative(A, C) = B
relative(A, C) = B 会计算从 A 到 C 路径应该执行怎样的路径 B
resolve('/data/orandea/test/aaa', '../../impl/bbb'),
//=> /data/orandea/impl/bbb
relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb')
//=> ../../impl/bbb为什么需要 path?
我们使用 path 主要原因是抹去平台差距。
POSIX 和 Windows 的路径是有差距的,使用 path 模块提供的方法可以帮我们抹去差距。
譬如进行路径分割的时候,无需关心到底使用 \ 还是 /,其他 path 导出的方法也类似。
// in POSIX
'foo/bar/baz'.split(path.sep);
// Returns: ['foo', 'bar', 'baz']
// in Windows
'foo\\bar\\baz'.split(path.sep);
// Returns: ['foo', 'bar', 'baz']Windows vs. POSIX
nodejs 还提供了互相调用了一个平台的能力,互相可以调用对方平台的路径解析算法
通常来说,在 POSIX 上的程序处理的路径都是 POSIX 的路径, 在 Windows 上的程序处理的路径都是 Windows 的路径,一般不会有问题
但是如果在 POSIX 上要处理 Windows 上的路径(交换同理),就会有问题,比如:
import path from 'path'
// 在 POSIX 的机器上,处理 Windows 的路径,我们会得到不符合预期的答案
path.basename('C:\\temp\\myfile.html');
//=> C:\\temp\\myfile.html
// 应该调用 win 平台的算法
path.win32.basename('C:\\temp\\myfile.html')
//=> myfile.htmlTIP
上面的例子不代表你需要写两套代码,当用户通过 npm 安装你的工具的时候,平台还是根据用户的操作系统使用正确的算法,只有尝试解析和本平台不同风格的路径才会出现问题