无法读取双重嵌套目录:Node.js递归遍历文件系统逻辑排查
问题分析与修复
核心错误是递归调用时传递的目录路径不正确:
当你递归调用readdir(dirContent[i], path)时,dirContent[i]只是当前目录下的子目录名称,不是完整路径。Node.js的fs.readdirSync会以当前工作目录为基准去查找这个目录,而不是在父目录下查找,所以会出现找不到文件的ENOENT错误。
除此之外还有几个逻辑问题需要一并修复:
- 每次递归都重复读取
.gitignore,效率极低 - 递归获取的子目录文件没有合并到上层缓存中,最终
global.cache只会保存最外层目录的文件 - 手动拼接路径容易出现格式问题(比如多余的
/) .gitignore的匹配逻辑太简单,没有处理空行和实际的忽略规则(比如目录下的所有文件)
修复后的代码示例
import fs from 'fs'; import path from 'path'; type Cache = { path: string; content: Buffer; }; // 提前读取并处理.gitignore规则,只执行一次 const ignoreRules = fs.readFileSync(".gitignore", "utf8") .split("\n") .map(line => line.trim()) .filter(line => line !== '' && !line.startsWith('#')); // 过滤空行和注释 ignoreRules.push(".git"); const isDir = (targetPath: string): boolean => { return fs.statSync(targetPath).isDirectory(); }; const readdir = (dir: string, currentDir: string): Cache[] => { const dirContent = fs.readdirSync(dir); const cache: Cache[] = []; dirContentLoop: for (const item of dirContent) { // 用path.join正确拼接路径,避免手动拼接的格式问题 const fullPath = path.join(currentDir, item); const relativePath = fullPath.replace(/^\.\//, ''); // 去掉开头的./ // 检查是否需要忽略当前文件/目录 for (const rule of ignoreRules) { // 支持精确匹配和目录下所有文件的忽略 if (relativePath === rule || relativePath.startsWith(`${rule}/`)) { continue dirContentLoop; } } if (isDir(fullPath)) { // 递归调用时,传递子目录的完整路径,并合并结果到当前缓存 const subCache = readdir(path.join(dir, item), fullPath); cache.push(...subCache); continue; } cache.push({ path: relativePath, content: fs.readFileSync(fullPath) }); } return cache; }; // 调用示例:读取当前目录 global.cache = readdir('./', './');
关键修复点说明
- 递归路径修正:递归调用时用
path.join(dir, item)作为新的dir参数,确保是子目录的完整路径,Node.js能正确找到该目录。 - 缓存合并:递归调用返回子目录的缓存数组,用
push(...subCache)合并到当前缓存,保证最终结果包含所有层级的文件。 - 忽略规则优化:提前读取
.gitignore并过滤无效行,同时支持目录下所有文件的忽略(比如匹配node_modules/时,其下所有文件都被忽略)。 - 路径安全拼接:用
path.join处理路径,避免手动拼接导致的格式错误。
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

