Node.js Path 模块

108 阅读3分钟

Path 模块是 Node.js 的核心模块之一,提供了一系列处理文件和目录路径的工具方法。以下是 Path 模块常用方法的详细介绍及实际使用示例。

1. 引入 Path 模块

const path = require('path');

2. 常用方法及示例

2.1 path.join([...paths])

作用:将多个路径片段连接成一个规范的路径字符串。

特点

  • 自动处理不同操作系统的路径分隔符
  • 自动处理多余的...
  • 自动处理路径分隔符

示例

console.log(path.join('/usr', 'local', 'bin')); 
// 输出: /usr/local/bin (Linux/macOS) 或 \usr\local\bin (Windows)

console.log(path.join('src', '..', 'public', 'images'));
// 输出: public/images

console.log(path.join(__dirname, 'config', 'app.json'));
// 输出: 当前目录/config/app.json 的绝对路径

2.2 path.resolve([...paths])

作用:将路径或路径片段解析为绝对路径。

特点

  • 从右到左处理路径片段
  • 如果处理完所有片段后还不是绝对路径,则使用当前工作目录
  • 忽略空字符串

示例

console.log(path.resolve('/foo/bar', './baz'));
// 输出: /foo/bar/baz

console.log(path.resolve('/foo/bar', '/tmp/file/'));
// 输出: /tmp/file

console.log(path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'));
// 假设当前工作目录是 /home/mysite,则输出: /home/mysite/wwwroot/static_files/gif/image.gif

console.log(path.resolve(__dirname, 'src/index.js'));
// 输出: 当前文件所在目录/src/index.js 的绝对路径

2.3 path.dirname(path)

作用:返回路径的目录名。

示例

console.log(path.dirname('/foo/bar/baz/quux.html'));
// 输出: /foo/bar/baz

console.log(path.dirname('C:\\temp\\myfile.html'));
// 输出: C:\temp

console.log(path.dirname(__filename));
// 输出: 当前文件所在的目录路径

2.4 path.basename(path[, ext])

作用:返回路径的最后一部分,可以去掉指定的扩展名。

示例

console.log(path.basename('/foo/bar/baz/quux.html'));
// 输出: quux.html

console.log(path.basename('/foo/bar/baz/quux.html', '.html'));
// 输出: quux

console.log(path.basename('C:\\temp\\myfile.html'));
// 输出: myfile.html

console.log(path.basename(__filename));
// 输出: 当前文件名

2.5 path.extname(path)

作用:返回路径的扩展名(包括点)。

示例

console.log(path.extname('index.html'));
// 输出: .html

console.log(path.extname('index.coffee.md'));
// 输出: .md

console.log(path.extname('index.'));
// 输出: .

console.log(path.extname('index'));
// 输出: '' (空字符串)

console.log(path.extname('.index'));
// 输出: '' (空字符串)

2.6 path.parse(path)

作用:将路径解析为一个对象,包含 root、dir、base、ext、name 属性。

示例

const parsed = path.parse('/home/user/dir/file.txt');
console.log(parsed);
/*
输出:
{
  root: '/',
  dir: '/home/user/dir',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
}
*/

const winParsed = path.parse('C:\\path\\dir\\file.txt');
console.log(winParsed);
/*
输出:
{
  root: 'C:\\',
  dir: 'C:\\path\\dir',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
}
*/

2.7 path.format(pathObject)

作用:从对象生成路径字符串,是 path.parse 的反向操作。

示例

const obj = {
  root: '/',
  dir: '/home/user/dir',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
};
console.log(path.format(obj));
// 输出: /home/user/dir/file.txt

2.8 path.normalize(path)

作用:规范化路径,处理 ... 和多余的分隔符。

示例

console.log(path.normalize('/foo/bar//baz/asdf/quux/..'));
// 输出: /foo/bar/baz/asdf

console.log(path.normalize('C:\\temp\\\\foo\\bar\\..\\'));
// 输出: C:\temp\foo\

2.9 path.isAbsolute(path)

作用:判断路径是否是绝对路径。

示例

console.log(path.isAbsolute('/foo/bar')); // true
console.log(path.isAbsolute('C:/foo/bar')); // true (Windows)
console.log(path.isAbsolute('foo/bar')); // false
console.log(path.isAbsolute('./foo/bar')); // false

2.10 path.relative(from, to)

作用:返回从 from 到 to 的相对路径。

示例

console.log(path.relative('/data/orandea/test/aaa', '/data/orandea/impl/bbb'));
// 输出: ../../impl/bbb

console.log(path.relative('C:\\orandea\\test\\aaa', 'C:\\orandea\\impl\\bbb'));
// 输出: ..\..\impl\bbb

2.11 path.seppath.delimiter

作用

  • path.sep:提供平台特定的路径片段分隔符(\/
  • path.delimiter:提供平台特定的路径分隔符(;:

示例

console.log(path.sep); 
// 输出: \ (Windows) 或 / (POSIX)

console.log(path.delimiter);
// 输出: ; (Windows) 或 : (POSIX)

// 分割PATH环境变量
console.log(process.env.PATH.split(path.delimiter));

3. 实际应用示例

3.1 构建文件上传路径

const uploadDir = path.join(__dirname, '..', 'public', 'uploads');

function getUploadPath(filename) {
  return path.join(uploadDir, Date.now() + path.extname(filename));
}

// 使用
const filePath = getUploadPath('avatar.png');
console.log(filePath);
// 输出类似: /project/public/uploads/1623456789012.png

3.2 动态加载配置文件

const configPath = path.resolve(process.cwd(), 'config', process.env.NODE_ENV + '.json');
const config = require(configPath);

3.3 处理用户上传的文件扩展名

function isImageFile(filename) {
  const ext = path.extname(filename).toLowerCase();
  return ['.jpg', '.jpeg', '.png', '.gif'].includes(ext);
}

console.log(isImageFile('avatar.png')); // true
console.log(isImageFile('document.pdf')); // false

3.4 构建安全的文件路径(防止目录遍历攻击)

const publicDir = path.resolve(__dirname, 'public');

function getSafePath(userInput) {
  const requestedPath = path.join(publicDir, userInput);
  if (!requestedPath.startsWith(publicDir)) {
    throw new Error('Invalid path');
  }
  return requestedPath;
}

// 使用
try {
  const safePath = getSafePath('../secret.txt'); // 会抛出错误
} catch (err) {
  console.error(err.message);
}

3.5 跨平台路径处理

// 假设有一个配置文件中存储了路径
const config = {
  logDir: 'logs\\app' // Windows风格的路径
};

// 转换为当前平台的正确路径
const logDir = path.normalize(config.logDir);

console.log(logDir); 
// 在Windows上输出: logs\app
// 在Linux/macOS上输出: logs/app

4. 注意事项

  1. 跨平台兼容性:始终使用 path 模块的方法而不是手动拼接路径字符串
  2. 路径规范化:在处理用户输入的路径时,总是先规范化路径
  3. 安全性:检查解析后的路径是否在预期目录内,防止目录遍历攻击
  4. 性能path 模块的方法是高度优化的,通常比正则表达式或字符串操作更高效