在Node.js项目开发中,操作子目录是非常常见的需求,比如项目初始化时创建多级目录、读取某个目录下的所有子目录和文件、清理临时子目录等。这些操作不需要额外安装第三方库,使用Node.js内置的fs模块和path模块就能完成,下面我们逐一讲解具体的实现方法。

前置知识:核心模块介绍
操作子目录主要依赖两个内置模块:
fs模块:负责文件系统的操作,比如创建目录、读取目录内容、删除目录等,Node.js 10+版本推荐使用fs.promisesAPI,基于Promise实现,避免回调地狱。path模块:负责处理文件路径,解决不同操作系统路径分隔符差异的问题,避免手动拼接路径导致的错误。
基础操作:创建和删除子目录
创建单层子目录
如果只需要创建单个子目录,可以使用fs.promises.mkdir方法,该方法接收目录路径和可选配置参数,返回Promise对象。
const fs = require('fs').promises;
const path = require('path');
// 创建单层子目录,目录已存在时会报错
async function createSingleSubDir() {
try {
// 拼接子目录路径,当前目录下的test_sub_dir
const subDirPath = path.join(__dirname, 'test_sub_dir');
await fs.mkdir(subDirPath);
console.log('单层子目录创建成功');
} catch (err) {
console.error('创建子目录失败:', err.message);
}
}
createSingleSubDir();创建多层嵌套子目录
如果需要创建多级子目录,比如a/b/c这样的结构,只需要在mkdir的配置中设置recursive: true,Node.js会自动创建所有不存在的父目录。
const fs = require('fs').promises;
const path = require('path');
// 创建多层嵌套子目录
async function createMultiSubDir() {
try {
const multiDirPath = path.join(__dirname, 'parent_dir', 'child_dir', 'grandchild_dir');
// recursive设为true,自动创建所有缺失的父目录
await fs.mkdir(multiDirPath, { recursive: true });
console.log('多层嵌套子目录创建成功');
} catch (err) {
console.error('创建多层子目录失败:', err.message);
}
}
createMultiSubDir();删除子目录
删除子目录时需要注意,fs.promises.rmdir默认只能删除空目录,如果目录中有文件或子目录,需要设置recursive: true(Node.js 12.10+支持)来递归删除所有内容。
const fs = require('fs').promises;
const path = require('path');
// 删除子目录,包含目录内的所有内容
async function deleteSubDir() {
try {
const targetDirPath = path.join(__dirname, 'parent_dir');
// recursive设为true,递归删除目录及所有内容
await fs.rm(targetDirPath, { recursive: true, force: true });
console.log('子目录删除成功');
} catch (err) {
console.error('删除子目录失败:', err.message);
}
}
deleteSubDir();读取子目录内容
如果需要获取子目录下的所有文件和子目录列表,可以使用fs.promises.readdir方法,该方法返回目录下的内容数组,还可以通过配置返回更详细的信息。
读取子目录名称列表
const fs = require('fs').promises;
const path = require('path');
// 读取子目录下的所有内容名称
async function readSubDirNames() {
try {
const dirPath = path.join(__dirname, 'test_sub_dir');
// 读取目录内容,默认返回名称数组
const dirContents = await fs.readdir(dirPath);
console.log('子目录内容名称:', dirContents);
} catch (err) {
console.error('读取子目录失败:', err.message);
}
}
readSubDirNames();读取子目录详细信息
如果需要区分内容是文件还是子目录,以及获取大小、修改时间等信息,可以设置withFileTypes: true,返回的是fs.Dirent对象数组,通过对象的isFile、isDirectory方法判断类型。
const fs = require('fs').promises;
const path = require('path');
// 读取子目录内容并区分文件/目录
async function readSubDirDetails() {
try {
const dirPath = path.join(__dirname, 'test_sub_dir');
// withFileTypes设为true,返回Dirent对象数组
const dirEntries = await fs.readdir(dirPath, { withFileTypes: true });
dirEntries.forEach(entry => {
const type = entry.isDirectory() ? '子目录' : '文件';
console.log(`${entry.name} 是 ${type}`);
});
} catch (err) {
console.error('读取子目录详细信息失败:', err.message);
}
}
readSubDirDetails();进阶操作:遍历所有子目录和文件
实际开发中经常需要遍历某个目录下的所有子目录和文件,比如统计项目中的所有JS文件数量,这时候需要递归遍历目录结构。
const fs = require('fs').promises;
const path = require('path');
// 递归遍历目录,获取所有文件路径
async function traverseAllSubDirs(rootPath) {
const result = [];
// 内部递归函数
async function traverse(currentPath) {
try {
const entries = await fs.readdir(currentPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(currentPath, entry.name);
if (entry.isDirectory()) {
// 是子目录,继续递归遍历
await traverse(fullPath);
} else {
// 是文件,加入结果数组
result.push(fullPath);
}
}
} catch (err) {
console.error(`遍历路径${currentPath}失败:`, err.message);
}
}
await traverse(rootPath);
return result;
}
// 使用示例
async function main() {
const rootDir = path.join(__dirname, 'test_sub_dir');
const allFiles = await traverseAllSubDirs(rootDir);
console.log('所有文件路径:', allFiles);
}
main();注意事项
- 路径拼接必须使用
path.join或者path.resolve,不要手动拼接字符串,避免Windows和Linux系统路径分隔符不兼容的问题。 - 操作目录前最好先判断目录是否存在,可以使用
fs.promises.access方法检查,避免不必要的报错。 - 删除目录时如果使用
recursive: true要谨慎,确认路径正确,避免误删重要文件。 - 遍历大规模目录时注意性能,避免同时发起过多异步操作,可以适当添加并发控制。