Copy // ./getDirFiles.js
import { promises as fsPromises } from 'fs'
type DirInfo = {
dirPath: string | null, // 所在文件夹路径
path: string, // 所在文件夹路径+名称+后缀名
fullName: string, // 名字+后缀名,也就是下面的 [name].[suffix]
name: string, // 纯名称不带后缀名
suffix: null | string, // 后缀名
isDir: boolean, // 是否是文件夹
paraent: DirInfo | null, // 父级目录信息
children: null | DirInfo[], // 子文件数组
}
// 过滤用的方法,不传则默认使用这个方法,此方法返回true则保留,否则忽略
// 注意,如果项是方法,则传给方法的info.children是null,免得消耗性能获取了children,结果这个文件夹名字被过滤了。
const filterHandler = (info: DirInfo) => {
// 要忽略的文件、文件夹名称
let ignoreNameArr = [
'.git',
'node_modules',
'.DS_Store',
'.vscode',
'.idea',
];
if (ignoreNameArr.includes(info.fullName)) return false
return true
}
/**
* 提供文件夹路径,这里递归遍历文件夹,得到所有递归文件信息
* @returns
* dirPath: 所在文件夹路径
* path: 所在文件夹路径+名称+后缀名
* fullName: 名字+后缀名,也就是下面的 [name].[suffix]
* name: 纯名称不带后缀名
* suffix: 后缀名
* isDir: 是否是文件夹
* paraent: 父级目录信息
* children: 子文件数组
*/
const getDirFiles = (() => {
// 读取路径下的文件夹、文件名称数组
async function readdir(path: string): Promise<[boolean, string[] | any]> {
try {
let dirArr = await fsPromises.readdir(path)
return [true, dirArr]
} catch(error) {
return [false, error]
}
}
/**
* 判断路径是否存在/是否是文件夹
* @param {String} path 文件地址 + 名称 + 后缀名
* @return {Array[Boolean, Boolean]} 返回数组[是否存在, 是否是文件夹]
*/
async function pathType(path: string): Promise<[boolean, boolean | any]> {
try {
const stat = await fsPromises.stat(path)
const isDir = stat.isDirectory()
return [true, isDir]
} catch(error) {
return [false, error]
}
}
return async (dirPath: string, _filterHandler = filterHandler): Promise<DirInfo[]> => {
async function one(tempPath: string, paraent: DirInfo | null = null): Promise<DirInfo[]> {
// 获取文件夹内部直接子文件、文件夹的名称字符串数组
let [success, data] = await readdir(tempPath)
let fileNameArr = []
if (success) fileNameArr = data || []
let children = []
for (let fullName of fileNameArr) {
let filePath = `${tempPath}/${fullName}`
const typeInfo = await pathType(filePath)
if (!typeInfo) continue
let info: DirInfo = {
dirPath: tempPath, // 所在文件夹路径
path: filePath, // 所在文件夹路径+名称+后缀名
fullName, // 名字+后缀名,也就是下面的 [name].[suffix]
name: '', // 纯名称不带后缀名
suffix: null, // 后缀名
isDir: typeInfo[1], // 是否是文件夹
paraent, // 父级目录信息
children: null, // 子文件数组
}
// 是文件夹
if (info.isDir) {
info.name = fullName
// 过滤文件是否要忽略
const needKeep = _filterHandler(info)
if (!needKeep) continue
info.children = await one(filePath, info) || []
} else {
let name = fullName.substring(0, fullName.lastIndexOf('.'))
info.name = name || fullName
info.suffix = fullName.substring(fullName.lastIndexOf('.') + 1)
info.children = null
// 过滤文件是否要忽略
const needKeep = _filterHandler(info)
if (!needKeep) continue
}
children.push(info)
}
return children
}
const dirInfo = await one(dirPath, null)
return dirInfo
}
})();
export default getDirFiles