Node.js 工具模块详解

Node.js 提供了丰富的内置模块,帮助开发者高效处理各种常见任务。本文将详细介绍五个重要的工具模块:path (路径处理)、url (URL解析)、querystring (查询字符串)、util (工具函数)和 os(操作系统信息)。

一、path 模块:路径处理

path 模块提供了用于处理和转换文件路径的实用工具。它最大的优势是跨平台兼容性 ,能够自动处理不同操作系统的路径分隔符(Windows 使用 \,Unix/Linux/macOS 使用 /)。

1.1 引入模块

javascript 复制代码
const path = require('path');

1.2 常用方法

path.join([...paths]) - 连接路径片段

将多个路径片段连接成一个完整的路径,自动处理路径分隔符和相对路径。

javascript 复制代码
const path = require('path');

// 基本用法
console.log(path.join('/users', 'john', 'docs', 'file.txt'));
// Unix/Linux/macOS: /users/john/docs/file.txt
// Windows: 如果第一个参数是绝对路径,结果取决于平台

// 跨平台推荐用法(使用相对路径)
console.log(path.join('users', 'john', 'docs', 'file.txt'));
// 所有平台: users/john/docs/file.txt(相对路径)

// 使用 __dirname 构建绝对路径
console.log(path.join(__dirname, 'docs', 'file.txt'));
// 输出: 当前文件所在目录/docs/file.txt

// 处理相对路径
console.log(path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'));
// 输出: /foo/bar/baz/asdf

// 处理当前目录和父目录
console.log(path.join(__dirname, '..', 'config', 'app.json'));
// 输出: 当前目录的父目录下的 config/app.json

path.resolve([...paths]) - 解析为绝对路径

将路径或路径片段解析为绝对路径。如果所有路径片段都是相对路径,则相对于当前工作目录解析。

javascript 复制代码
const path = require('path');

// 从右到左处理路径,直到构造出绝对路径
console.log(path.resolve('foo/bar', '/tmp/file/', '..', 'a/../subfile'));
// 输出: /tmp/subfile

// 如果所有路径都是相对路径,则相对于当前工作目录
console.log(path.resolve('wwwroot', 'static_files/png/', '../gif/image.gif'));
// 如果当前目录是 /home/myself/node,则输出:
// /home/myself/node/wwwroot/static_files/gif/image.gif

// 常用:解析相对于当前文件的路径
const configPath = path.resolve(__dirname, 'config.json');

path.basename(path[, ext]) - 获取文件名

返回路径的最后一部分(文件名)。可选的 ext 参数用于去除文件扩展名。

javascript 复制代码
const path = require('path');

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

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

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

path.dirname(path) - 获取目录名

返回路径的目录部分。

javascript 复制代码
const path = require('path');

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

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

path.extname(path) - 获取扩展名

返回路径中文件的扩展名(包括点号)。

javascript 复制代码
const path = require('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'));
// 输出: ''

path.parse(path) - 解析路径对象

将路径字符串解析为一个对象,包含 rootdirbaseextname 等属性。

javascript 复制代码
const path = require('path');

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

// Windows 示例
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'
// }

path.format(pathObject) - 格式化路径对象

path.parse() 相反,将路径对象格式化为路径字符串。

javascript 复制代码
const path = require('path');

const pathObject = {
  root: '/',
  dir: '/home/user/dir',
  base: 'file.txt',
  ext: '.txt',
  name: 'file'
};

console.log(path.format(pathObject));
// 输出: '/home/user/dir/file.txt'

path.normalize(path) - 规范化路径

规范化路径字符串,解析 ... 片段,并处理多余的路径分隔符。

javascript 复制代码
const path = require('path');

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

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

path.isAbsolute(path) - 判断是否为绝对路径

判断路径是否为绝对路径。

javascript 复制代码
const path = require('path');

console.log(path.isAbsolute('/foo/bar')); // true
console.log(path.isAbsolute('/baz/..'));  // true
console.log(path.isAbsolute('qux/'));     // false
console.log(path.isAbsolute('.'));        // false

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

path.relative(from, to) - 计算相对路径

计算从 fromto 的相对路径。

javascript 复制代码
const path = require('path');

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'));
// Windows 输出: '..\\..\\impl\\bbb'

1.3 特殊变量

  • __dirname:当前模块的目录名(CommonJS)
  • __filename:当前模块的文件名(CommonJS)
javascript 复制代码
const path = require('path');

// 获取当前文件的目录
console.log(__dirname);
// 输出: /path/to/current/directory

// 获取当前文件的完整路径
console.log(__filename);
// 输出: /path/to/current/directory/file.js

// 构建相对于当前文件的路径
const configPath = path.join(__dirname, 'config', 'app.json');

1.4 实用示例

javascript 复制代码
const path = require('path');
const fs = require('fs').promises;

// 示例1:安全地构建文件路径
async function readConfig() {
  const configPath = path.join(__dirname, 'config', 'app.json');
  const data = await fs.readFile(configPath, 'utf8');
  return JSON.parse(data);
}

// 示例2:获取文件信息
function getFileInfo(filePath) {
  return {
    fullPath: path.resolve(filePath),
    dirname: path.dirname(filePath),
    basename: path.basename(filePath),
    extname: path.extname(filePath),
    name: path.basename(filePath, path.extname(filePath))
  };
}

console.log(getFileInfo('/home/user/docs/report.pdf'));
// 输出:
// {
//   fullPath: '/home/user/docs/report.pdf',
//   dirname: '/home/user/docs',
//   basename: 'report.pdf',
//   extname: '.pdf',
//   name: 'report'
// }

// 示例3:处理上传文件的扩展名
function isImageFile(filename) {
  const ext = path.extname(filename).toLowerCase();
  return ['.jpg', '.jpeg', '.png', '.gif', '.webp'].includes(ext);
}

console.log(isImageFile('photo.jpg'));  // true
console.log(isImageFile('document.pdf')); // false

二、url 模块:URL 解析

url 模块提供了用于解析和格式化 URL 的实用工具。Node.js 推荐使用 WHATWG URL API

2.1 引入模块

javascript 复制代码
// WHATWG URL API(推荐)
const { URL, URLSearchParams } = require('url');

2.2 WHATWG URL API(推荐)

new URL(input[, base]) - 创建 URL 对象

javascript 复制代码
const { URL } = require('url');

// 绝对 URL
const myURL = new URL('https://example.org:8080/p/a/t/h?query=string#hash');

console.log(myURL.href);        // 'https://example.org:8080/p/a/t/h?query=string#hash'
console.log(myURL.protocol);    // 'https:'
console.log(myURL.hostname);    // 'example.org'
console.log(myURL.port);        // '8080'
console.log(myURL.pathname);    // '/p/a/t/h'
console.log(myURL.search);      // '?query=string'
console.log(myURL.hash);        // '#hash'

// 相对 URL(需要提供 base)
const baseURL = 'https://example.org/foo/bar';
const relativeURL = new URL('../baz', baseURL);
console.log(relativeURL.href);  // 'https://example.org/foo/baz'

URL 对象属性

javascript 复制代码
const { URL } = require('url');
const myURL = new URL('https://user:pass@sub.example.com:8080/p/a/t/h?query=string#hash');

console.log(myURL.protocol);    // 'https:'
console.log(myURL.username);    // 'user'
console.log(myURL.password);    // 'pass'
console.log(myURL.host);        // 'sub.example.com:8080'
console.log(myURL.hostname);    // 'sub.example.com'
console.log(myURL.port);        // '8080'
console.log(myURL.pathname);    // '/p/a/t/h'
console.log(myURL.search);      // '?query=string'
console.log(myURL.searchParams); // URLSearchParams 对象
console.log(myURL.hash);        // '#hash'
console.log(myURL.origin);      // 'https://sub.example.com:8080'

URLSearchParams - 查询参数处理

URLSearchParams 提供了强大的查询字符串操作方法。

javascript 复制代码
const { URL, URLSearchParams } = require('url');

// 从 URL 对象获取查询参数
const myURL = new URL('https://example.com/?name=Kai&age=30&city=Beijing');
const params = myURL.searchParams;

// 获取参数值
console.log(params.get('name'));     // 'Kai'
console.log(params.get('age'));     // '30'
console.log(params.has('city'));    // true

// 设置参数
params.set('age', '31');
params.set('email', 'kai@example.com');

// 追加参数
params.append('hobby', 'coding');
params.append('hobby', 'reading');

// 删除参数
params.delete('city');

// 获取所有值
console.log(params.getAll('hobby')); // ['coding', 'reading']

// 遍历参数
for (const [key, value] of params) {
  console.log(`${key}: ${value}`);
}

// 转换为字符串
console.log(params.toString());
// 输出: 'name=Kai&age=31&email=kai%40example.com&hobby=coding&hobby=reading'

// 排序
params.sort();
console.log(params.toString());

独立使用 URLSearchParams

javascript 复制代码
const { URLSearchParams } = require('url');

// 从字符串创建
const params1 = new URLSearchParams('foo=bar&abc=xyz&abc=123');
console.log(params1.get('foo'));      // 'bar'
console.log(params1.getAll('abc'));   // ['xyz', '123']

// 从对象创建
const params2 = new URLSearchParams({
  user: 'admin',
  password: 'secret123'
});
console.log(params2.toString());     // 'user=admin&password=secret123'

// 从 Map 创建
const map = new Map([
  ['name', 'John'],
  ['age', '30']
]);
const params3 = new URLSearchParams(map);
console.log(params3.toString());      // 'name=John&age=30'

2.3 实用示例

javascript 复制代码
const { URL, URLSearchParams } = require('url');

// 示例1:构建带查询参数的 URL
function buildURL(baseURL, params) {
  const url = new URL(baseURL);
  Object.keys(params).forEach(key => {
    url.searchParams.set(key, params[key]);
  });
  return url.href;
}

console.log(buildURL('https://api.example.com/users', {
  page: '1',
  limit: '10',
  sort: 'name'
}));
// 输出: 'https://api.example.com/users?page=1&limit=10&sort=name'

// 示例2:解析和修改 URL
function updateURLPort(urlString, newPort) {
  const url = new URL(urlString);
  url.port = newPort;
  return url.href;
}

console.log(updateURLPort('https://example.com:8080/path', '3000'));
// 输出: 'https://example.com:3000/path'

// 示例3:验证 URL
function isValidURL(str) {
  try {
    new URL(str);
    return true;
  } catch {
    return false;
  }
}

console.log(isValidURL('https://example.com'));  // true
console.log(isValidURL('not-a-url'));           // false

// 示例4:提取域名
function getDomain(urlString) {
  const url = new URL(urlString);
  return url.hostname;
}

console.log(getDomain('https://www.example.com:8080/path?query=1'));
// 输出: 'www.example.com'

三、querystring 模块:查询字符串处理

querystring 模块提供了用于解析和格式化 URL 查询字符串的实用工具。虽然 URLSearchParams 更现代,但 querystring 模块在处理自定义分隔符时仍然有用。

3.1 引入模块

javascript 复制代码
const querystring = require('querystring');

3.2 常用方法

querystring.parse(str[, sep[, eq[, options]]]) - 解析查询字符串

将查询字符串解析为对象。

javascript 复制代码
const querystring = require('querystring');

// 基本用法
const qs = 'year=2017&month=february&day=15';
const parsed = querystring.parse(qs);
console.log(parsed);
// 输出: { year: '2017', month: 'february', day: '15' }
console.log(parsed.year);   // '2017'
console.log(parsed.month);   // 'february'

// 自定义分隔符
const customQS = 'year:2017;month:february';
const parsed2 = querystring.parse(customQS, ';', ':');
console.log(parsed2);
// 输出: { year: '2017', month: 'february' }

// 解码选项
const encodedQS = 'name=John%20Doe&city=New%20York';
const parsed3 = querystring.parse(encodedQS);
console.log(parsed3);
// 输出: { name: 'John Doe', city: 'New York' }

querystring.stringify(obj[, sep[, eq[, options]]]) - 序列化为查询字符串

将对象序列化为查询字符串。

javascript 复制代码
const querystring = require('querystring');

// 基本用法
const obj = {
  year: 2017,
  month: 'february',
  day: 15
};
const qs = querystring.stringify(obj);
console.log(qs);
// 输出: 'year=2017&month=february&day=15'

// 自定义分隔符
const customQS = querystring.stringify(obj, ';', ':');
console.log(customQS);
// 输出: 'year:2017;month:february;day:15'

// 编码选项
const obj2 = {
  name: 'John Doe',
  city: 'New York'
};
const encodedQS = querystring.stringify(obj2);
console.log(encodedQS);
// 输出: 'name=John%20Doe&city=New%20York'

// 处理数组
const obj3 = {
  tags: ['nodejs', 'javascript', 'web']
};
console.log(querystring.stringify(obj3));
// 输出: 'tags=nodejs&tags=javascript&tags=web'

querystring.escape(str) - URL 编码

对字符串进行 URL 编码(通常不需要直接调用,stringify 会自动处理)。

javascript 复制代码
const querystring = require('querystring');

console.log(querystring.escape('hello world'));
// 输出: 'hello%20world'

console.log(querystring.escape('foo@bar.com'));
// 输出: 'foo%40bar.com'

querystring.unescape(str) - URL 解码

对字符串进行 URL 解码(通常不需要直接调用,parse 会自动处理)。

javascript 复制代码
const querystring = require('querystring');

console.log(querystring.unescape('hello%20world'));
// 输出: 'hello world'

console.log(querystring.unescape('foo%40bar.com'));
// 输出: 'foo@bar.com'

3.3 实用示例

javascript 复制代码
const querystring = require('querystring');

// 示例1:解析 URL 查询字符串
function parseQueryString(urlString) {
  const queryString = urlString.split('?')[1] || '';
  return querystring.parse(queryString);
}

const url = 'https://example.com/search?q=nodejs&page=1&limit=10';
const params = parseQueryString(url);
console.log(params);
// 输出: { q: 'nodejs', page: '1', limit: '10' }

// 示例2:构建查询字符串
function buildQueryString(params) {
  return querystring.stringify(params);
}

const searchParams = {
  q: 'nodejs tutorial',
  page: 1,
  sort: 'relevance'
};
console.log(buildQueryString(searchParams));
// 输出: 'q=nodejs%20tutorial&page=1&sort=relevance'

// 示例3:合并查询参数
function mergeQueryParams(baseParams, newParams) {
  const merged = { ...baseParams, ...newParams };
  return querystring.stringify(merged);
}

const base = { page: 1, limit: 10 };
const additional = { sort: 'name', order: 'asc' };
console.log(mergeQueryParams(base, additional));
// 输出: 'page=1&limit=10&sort=name&order=asc'

// 示例4:处理嵌套对象(需要自定义序列化)
function stringifyNested(obj, prefix = '') {
  const pairs = [];
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const value = obj[key];
      const newKey = prefix ? `${prefix}[${key}]` : key;
      
      if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
        pairs.push(...stringifyNested(value, newKey));
      } else if (Array.isArray(value)) {
        value.forEach((item, index) => {
          pairs.push(`${newKey}[${index}]=${encodeURIComponent(item)}`);
        });
      } else {
        pairs.push(`${newKey}=${encodeURIComponent(value)}`);
      }
    }
  }
  return pairs;
}

const nested = {
  user: {
    name: 'John',
    age: 30
  },
  tags: ['nodejs', 'javascript']
};
console.log(stringifyNested(nested).join('&'));
// 输出: 'user[name]=John&user[age]=30&tags[0]=nodejs&tags[1]=javascript'

四、util 模块:工具函数

util 模块提供了多种实用工具函数,帮助开发者处理常见的编程任务,如类型检查、调试、Promise 转换等。

4.1 引入模块

javascript 复制代码
const util = require('util');

4.2 常用方法

util.format(format[, ...args]) - 格式化字符串

返回格式化后的字符串,类似于 C 语言的 printf 函数。

javascript 复制代码
const util = require('util');

// 基本用法
console.log(util.format('%s:%s', 'foo', 'bar'));
// 输出: 'foo:bar'

console.log(util.format('%d + %d = %d', 1, 2, 3));
// 输出: '1 + 2 = 3'

// 占位符
// %s - 字符串
// %d - 数字(整数或浮点数)
// %j - JSON
// %% - 百分号
console.log(util.format('Name: %s, Age: %d, Data: %j', 'John', 30, { city: 'NYC' }));
// 输出: 'Name: John, Age: 30, Data: {"city":"NYC"}'

// 如果没有提供格式字符串,则将所有参数用空格连接
console.log(util.format('Hello', 'World', 123));
// 输出: 'Hello World 123'

util.inspect(object[, options]) - 对象检查

返回对象的字符串表示,通常用于调试。这是 console.log 内部使用的方法。

javascript 复制代码
const util = require('util');

const obj = {
  name: 'John',
  age: 30,
  nested: {
    city: 'NYC',
    hobbies: ['coding', 'reading']
  }
};

// 基本用法
console.log(util.inspect(obj));
// 输出: { name: 'John', age: 30, nested: { city: 'NYC', hobbies: [ 'coding', 'reading' ] } }

// 选项配置
console.log(util.inspect(obj, {
  colors: true,        // 使用颜色
  depth: 2,           // 最大递归深度
  compact: false,     // 每个属性一行
  showHidden: true,   // 显示不可枚举属性
  breakLength: 80     // 换行长度
}));

// 自定义 inspect 方法
class CustomObject {
  constructor(value) {
    this.value = value;
  }
  
  [util.inspect.custom]() {
    return `CustomObject(${this.value})`;
  }
}

const custom = new CustomObject(42);
console.log(util.inspect(custom));
// 输出: 'CustomObject(42)'

util.promisify(original) - Promise 化

将遵循错误优先回调风格的函数转换为返回 Promise 的函数。

javascript 复制代码
const util = require('util');
const fs = require('fs');

// 将回调函数转换为 Promise
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

// 使用 async/await
async function readConfig() {
  try {
    const data = await readFile('config.json', 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('读取文件失败:', error);
    throw error;
  }
}

// 使用 .then()
readFile('data.txt', 'utf8')
  .then(data => console.log(data))
  .catch(err => console.error(err));

// 自定义 Promise 化函数
function customFunction(arg, callback) {
  setTimeout(() => {
    if (arg > 0) {
      callback(null, arg * 2);
    } else {
      callback(new Error('参数必须大于0'));
    }
  }, 100);
}

const promisifiedCustom = util.promisify(customFunction);

promisifiedCustom(5)
  .then(result => console.log(result))  // 输出: 10
  .catch(err => console.error(err));

util.callbackify(original) - 回调化

promisify 相反,将返回 Promise 的函数转换为使用回调的函数。

javascript 复制代码
const util = require('util');
const fs = require('fs').promises;

// 将 Promise 函数转换为回调函数
const readFileCallback = util.callbackify(fs.readFile);

readFileCallback('file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('错误:', err);
    return;
  }
  console.log('数据:', data);
});

util.types - 类型检查

提供各种类型检查函数。

javascript 复制代码
const util = require('util');

// 检查是否为数组
console.log(util.types.isArrayBuffer(new ArrayBuffer()));  // true
console.log(util.types.isArrayBuffer([]));                 // false

// 检查是否为 Date 对象
console.log(util.types.isDate(new Date()));                // true
console.log(util.types.isDate(Date.now()));                // false

// 检查是否为 Map
console.log(util.types.isMap(new Map()));                  // true

// 检查是否为 Set
console.log(util.types.isSet(new Set()));                  // true

// 检查是否为 Promise
console.log(util.types.isPromise(Promise.resolve()));     // true

// 检查是否为 RegExp
console.log(util.types.isRegExp(/abc/));                   // true

// 检查是否为 String 对象
console.log(util.types.isStringObject(new String('foo'))); // true
console.log(util.types.isStringObject('foo'));             // false

util.debuglog(section) - 调试日志

创建一个调试日志函数,仅在设置了 NODE_DEBUG 环境变量时才会输出日志。

javascript 复制代码
const util = require('util');

const debuglog = util.debuglog('foo');

// 设置环境变量: NODE_DEBUG=foo node app.js
debuglog('Hello from foo [%d]', 123);
// 只有在设置了 NODE_DEBUG=foo 时才会输出

// 多个调试标签
const debug1 = util.debuglog('foo');
const debug2 = util.debuglog('bar');

debug1('这是 foo 的调试信息');
debug2('这是 bar 的调试信息');

// 运行: NODE_DEBUG=foo,bar node app.js

util.deprecate(fn, msg[, code]) - 标记为弃用

标记函数为已弃用,调用时会显示警告信息。

javascript 复制代码
const util = require('util');

const deprecatedFunction = util.deprecate(() => {
  console.log('这个函数已被弃用');
}, 'deprecatedFunction() 已弃用,请使用 newFunction() 代替');

deprecatedFunction();
// 输出警告: (node:12345) DeprecationWarning: deprecatedFunction() 已弃用,请使用 newFunction() 代替

4.3 实用示例

javascript 复制代码
const util = require('util');
const fs = require('fs');

// 示例1:深度克隆对象(使用 JSON 序列化,有局限性)
function deepClone(obj) {
  return JSON.parse(JSON.stringify(obj));
}
// 注意:此方法无法克隆函数、undefined、Symbol、Date 对象等
// 更好的方式:使用结构化克隆(Node.js 17+)或库如 lodash.cloneDeep

// 示例2:格式化错误对象
function formatError(error) {
  return util.inspect(error, {
    colors: true,
    depth: null
  });
}

try {
  throw new Error('Something went wrong');
} catch (err) {
  console.log(formatError(err));
}

// 示例3:批量 Promise 化
function promisifyAll(obj) {
  const promisified = {};
  for (const key in obj) {
    if (typeof obj[key] === 'function') {
      promisified[key] = util.promisify(obj[key].bind(obj));
    }
  }
  return promisified;
}

const fsPromises = promisifyAll(fs);
// 现在可以使用 fsPromises.readFile, fsPromises.writeFile 等

// 示例4:创建调试工具
function createDebugger(namespace) {
  const debug = util.debuglog(namespace);
  return {
    log: (...args) => debug(util.format(...args)),
    info: (...args) => debug(`[INFO] ${util.format(...args)}`),
    error: (...args) => debug(`[ERROR] ${util.format(...args)}`)
  };
}

const logger = createDebugger('app');
// 运行: NODE_DEBUG=app node app.js
logger.log('Application started');
logger.info('Processing request');
logger.error('An error occurred');

五、os 模块:操作系统信息

os 模块提供了与操作系统相关的信息和方法,允许开发者获取系统架构、平台、CPU 信息、内存使用情况、网络接口等。

5.1 引入模块

javascript 复制代码
const os = require('os');

5.2 常用方法和属性

os.platform() - 获取操作系统平台

返回操作系统平台标识符。

javascript 复制代码
const os = require('os');

console.log(os.platform());
// 可能的值:
// 'darwin' - macOS
// 'win32' - Windows
// 'linux' - Linux
// 'freebsd' - FreeBSD
// 'openbsd' - OpenBSD

os.arch() - 获取 CPU 架构

返回操作系统的 CPU 架构。

javascript 复制代码
const os = require('os');

console.log(os.arch());
// 可能的值:
// 'x64' - 64位
// 'arm' - ARM
// 'arm64' - ARM 64位
// 'ia32' - 32位

os.cpus() - 获取 CPU 信息

返回每个逻辑 CPU 内核的信息数组。

javascript 复制代码
const os = require('os');

const cpus = os.cpus();
console.log(`CPU 核心数: ${cpus.length}`);

cpus.forEach((cpu, index) => {
  console.log(`CPU ${index}:`);
  console.log(`  型号: ${cpu.model}`);
  console.log(`  速度: ${cpu.speed} MHz`);
  console.log(`  用户时间: ${cpu.times.user} ms`);
  console.log(`  系统时间: ${cpu.times.sys} ms`);
  console.log(`  空闲时间: ${cpu.times.idle} ms`);
});

// 计算 CPU 使用率
// 注意:此函数仅用于演示基本概念。实际应用中,CPU 使用率需要通过两次采样(间隔一段时间)来计算差值才能得到准确结果
function getCPUUsage() {
  const cpus = os.cpus();
  let totalIdle = 0;
  let totalTick = 0;
  
  cpus.forEach(cpu => {
    const times = cpu.times;
    totalIdle += times.idle;
    totalTick += times.user + times.nice + times.sys + times.idle + times.irq;
  });
  
  const idle = totalIdle / cpus.length;
  const total = totalTick / cpus.length;
  const usage = 100 - ~~(100 * idle / total);
  
  return usage;
}

os.totalmem() - 获取总内存

返回系统的总内存量(以字节为单位)。

javascript 复制代码
const os = require('os');

const totalMem = os.totalmem();
console.log(`总内存: ${(totalMem / 1024 / 1024 / 1024).toFixed(2)} GB`);

os.freemem() - 获取空闲内存

返回系统的空闲内存量(以字节为单位)。

javascript 复制代码
const os = require('os');

const freeMem = os.freemem();
console.log(`空闲内存: ${(freeMem / 1024 / 1024 / 1024).toFixed(2)} GB`);

// 计算内存使用率
function getMemoryUsage() {
  const total = os.totalmem();
  const free = os.freemem();
  const used = total - free;
  const usagePercent = (used / total * 100).toFixed(2);
  
  return {
    total: formatBytes(total),
    used: formatBytes(used),
    free: formatBytes(free),
    usagePercent: `${usagePercent}%`
  };
}

function formatBytes(bytes) {
  return `${(bytes / 1024 / 1024 / 1024).toFixed(2)} GB`;
}

os.hostname() - 获取主机名

返回操作系统的主机名。

javascript 复制代码
const os = require('os');

console.log(os.hostname());
// 输出: 'my-computer'

os.type() - 获取操作系统类型

返回操作系统的类型。

javascript 复制代码
const os = require('os');

console.log(os.type());
// 可能的值:
// 'Linux' - Linux
// 'Darwin' - macOS
// 'Windows_NT' - Windows

os.release() - 获取操作系统版本

返回操作系统的版本号。

javascript 复制代码
const os = require('os');

console.log(os.release());
// 输出: '5.4.0-74-generic' (Linux)
// 或: '20.6.0' (macOS)
// 或: '10.0.19043' (Windows)

os.uptime() - 获取系统运行时间

返回系统的运行时间(以秒为单位)。

javascript 复制代码
const os = require('os');

const uptime = os.uptime();
const days = Math.floor(uptime / 86400);
const hours = Math.floor((uptime % 86400) / 3600);
const minutes = Math.floor((uptime % 3600) / 60);
const seconds = uptime % 60;

console.log(`系统运行时间: ${days}天 ${hours}小时 ${minutes}分钟 ${seconds}秒`);

os.homedir() - 获取用户主目录

返回当前用户的主目录路径。

javascript 复制代码
const os = require('os');

console.log(os.homedir());
// Windows: 'C:\\Users\\username'
// Linux/macOS: '/home/username'

os.tmpdir() - 获取临时目录

返回操作系统的临时文件目录路径。

javascript 复制代码
const os = require('os');

console.log(os.tmpdir());
// Windows: 'C:\\Users\\username\\AppData\\Local\\Temp'
// Linux: '/tmp'
// macOS: '/var/folders/...'

os.networkInterfaces() - 获取网络接口

返回网络接口信息对象。

javascript 复制代码
const os = require('os');

const interfaces = os.networkInterfaces();

for (const name of Object.keys(interfaces)) {
  console.log(`接口: ${name}`);
  interfaces[name].forEach(iface => {
    // 兼容不同 Node.js 版本:family 可能是 'IPv4' 或 4
    const isIPv4 = iface.family === 'IPv4' || iface.family === 4;
    if (isIPv4 && !iface.internal) {
      console.log(`  IPv4: ${iface.address}`);
      console.log(`  子网掩码: ${iface.netmask}`);
    }
  });
}

// 获取本机 IP 地址
function getLocalIP() {
  const interfaces = os.networkInterfaces();
  for (const name of Object.keys(interfaces)) {
    for (const iface of interfaces[name]) {
      // 兼容不同 Node.js 版本:family 可能是 'IPv4' 或 4
      const isIPv4 = iface.family === 'IPv4' || iface.family === 4;
      if (isIPv4 && !iface.internal) {
        return iface.address;
      }
    }
  }
  return '127.0.0.1';
}

console.log(`本机 IP: ${getLocalIP()}`);

os.endianness() - 获取字节序

返回 CPU 的字节序。

javascript 复制代码
const os = require('os');

console.log(os.endianness());
// 'BE' - 大端序
// 'LE' - 小端序(常见)

os.EOL - 行尾标识符

返回操作系统的行尾标识符。

javascript 复制代码
const os = require('os');

console.log(os.EOL);
// Windows: '\r\n'
// Unix/Linux/macOS: '\n'

// 使用示例
const content = `第一行${os.EOL}第二行${os.EOL}第三行`;

5.3 实用示例

javascript 复制代码
const os = require('os');

// 示例1:系统信息汇总
// 获取本机 IP 地址的辅助函数
function getLocalIP() {
  const interfaces = os.networkInterfaces();
  for (const name of Object.keys(interfaces)) {
    for (const iface of interfaces[name]) {
      // 兼容不同 Node.js 版本:family 可能是 'IPv4' 或 4
      const isIPv4 = iface.family === 'IPv4' || iface.family === 4;
      if (isIPv4 && !iface.internal) {
        return iface.address;
      }
    }
  }
  return '127.0.0.1';
}

function getSystemInfo() {
  return {
    platform: os.platform(),
    arch: os.arch(),
    hostname: os.hostname(),
    type: os.type(),
    release: os.release(),
    uptime: formatUptime(os.uptime()),
    cpus: {
      count: os.cpus().length,
      model: os.cpus()[0].model
    },
    memory: {
      total: formatBytes(os.totalmem()),
      free: formatBytes(os.freemem()),
      used: formatBytes(os.totalmem() - os.freemem()),
      usagePercent: ((os.totalmem() - os.freemem()) / os.totalmem() * 100).toFixed(2) + '%'
    },
    network: getLocalIP()
  };
}

function formatBytes(bytes) {
  const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
  if (bytes === 0) return '0 B';
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
  return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
}

function formatUptime(seconds) {
  const days = Math.floor(seconds / 86400);
  const hours = Math.floor((seconds % 86400) / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  return `${days}天 ${hours}小时 ${minutes}分钟`;
}

console.log(getSystemInfo());

// 示例2:监控系统资源
// 计算 CPU 使用率的辅助函数(简化版本,实际使用时建议使用两次采样)
function getCPUUsage() {
  const cpus = os.cpus();
  let totalIdle = 0;
  let totalTick = 0;
  
  cpus.forEach(cpu => {
    const times = cpu.times;
    totalIdle += times.idle;
    totalTick += times.user + times.nice + times.sys + times.idle + times.irq;
  });
  
  const idle = totalIdle / cpus.length;
  const total = totalTick / cpus.length;
  const usage = 100 - ~~(100 * idle / total);
  
  return usage;
}

function monitorSystem(interval = 5000) {
  setInterval(() => {
    const memUsage = (os.totalmem() - os.freemem()) / os.totalmem() * 100;
    // 注意:getCPUUsage() 需要两次采样才能准确,这里仅作演示
    const cpuUsage = getCPUUsage();
    
    console.log(`内存使用率: ${memUsage.toFixed(2)}%`);
    console.log(`CPU 使用率: ${cpuUsage}%`);
    
    if (memUsage > 90) {
      console.warn('警告: 内存使用率过高!');
    }
    if (cpuUsage > 90) {
      console.warn('警告: CPU 使用率过高!');
    }
  }, interval);
}

// 示例3:根据平台选择不同的行为
function platformSpecificAction() {
  switch (os.platform()) {
    case 'win32':
      console.log('Windows 特定操作');
      // Windows 特定代码
      break;
    case 'darwin':
      console.log('macOS 特定操作');
      // macOS 特定代码
      break;
    case 'linux':
      console.log('Linux 特定操作');
      // Linux 特定代码
      break;
    default:
      console.log('其他平台');
  }
}

// 示例4:创建临时文件路径
const path = require('path');

function createTempFilePath(prefix = 'temp', suffix = '.txt') {
  const tmpDir = os.tmpdir();
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(7);
  return path.join(tmpDir, `${prefix}-${timestamp}-${random}${suffix}`);
}

// 示例5:检测系统负载
function getSystemLoad() {
  const cpus = os.cpus();
  const load = cpus.map(cpu => {
    const total = Object.values(cpu.times).reduce((a, b) => a + b);
    const usage = ((total - cpu.times.idle) / total * 100).toFixed(2);
    return parseFloat(usage);
  });
  
  const avgLoad = (load.reduce((a, b) => a + b, 0) / load.length).toFixed(2);
  
  return {
    perCore: load,
    average: parseFloat(avgLoad)
  };
}

console.log('系统负载:', getSystemLoad());

总结

本文详细介绍了 Node.js 中五个重要的工具模块:

  1. path 模块:处理文件路径,提供跨平台兼容性
  2. url 模块:解析和格式化 URL,推荐使用 WHATWG URL API
  3. querystring 模块:处理查询字符串的解析和序列化
  4. util 模块:提供各种实用工具函数,如类型检查、Promise 转换、调试等
  5. os 模块:获取操作系统相关信息,如平台、CPU、内存等

这些模块都是 Node.js 的内置模块,无需安装即可使用。熟练掌握这些模块能够大大提高开发效率,让代码更加健壮和可维护。

最佳实践建议

  1. 路径处理 :始终使用 path.join()path.resolve() 而不是字符串拼接
  2. URL 处理 :使用 WHATWG URL API(URLURLSearchParams
  3. 查询字符串 :对于简单场景使用 querystring,复杂场景使用 URLSearchParams
  4. 异步转换 :使用 util.promisify() 将回调函数转换为 Promise
  5. 系统信息 :使用 os 模块进行跨平台兼容性处理
  6. 继承 :使用 ES6 的 classextends 语法,而不是已弃用的 util.inherits()

参考资源:

相关推荐
鹿鹿鹿鹿isNotDefined2 小时前
Antd5.x 在 Next.js14.x 项目中,初次渲染样式丢失
前端·react.js·next.js
谷歌开发者2 小时前
Web 开发指向标|AI 辅助功能在性能面板中的使用与功能
前端·人工智能
OpenTiny社区2 小时前
TinyEngine2.9版本发布:更智能,更灵活,更开放!
前端·vue.js·低代码
被考核重击3 小时前
浏览器原理
前端·笔记·学习
网络研究院3 小时前
Firefox 146 为 Windows 用户引入了加密本地备份功能
前端·windows·firefox
Mr.Jessy3 小时前
JavaScript高级:深入对象与内置构造函数
开发语言·前端·javascript·ecmascript
幸运小圣3 小时前
深入理解ref、reactive【Vue3工程级指南】
前端·javascript·vue.js
用户47949283569153 小时前
面试官最爱挖的坑:用户 Token 到底该存哪?
前端·javascript·面试
Irene19913 小时前
Web前端开发中的垃圾回收详解
前端