从node目录删除学习深度优先遍历和广度优先遍历处理任务思想。
使用到的模块:fs
path
使用到的方法:(均为同步方法)
let statObj = fs.statSync(path)
:判断是文件夹还是文件 statObj.isDirectory()
statObj.isFile()
fs.readdirSync(dir)
:返回值是一个数组,用来获取当前目录下的子目录或者文件。
fs.rmdirSync(dir)
:删除文件夹,注意:只能删除空文件夹,不能删除含有内容的文件夹,因此删除文件夹采用先删除子文件及子目录再删除父级文件目录。
fs.unlinkSync(dir)
:删除文件
path.join(path1,path2)
:将所有path片段拼接在一起,生成规范目录。
深度优先删除目录
思路:如下图所示结构,深度优先遍历思路就是从根节点A触发,找到B之后,继续沿着B往下找,找到E继续沿着E往下找,发现E没有子节点,那么就将E删除,接着删除F,再删除B,再去找C及其子节点,然后是D及其子节点。
深度优先遍历
function rmDirDeepSync(dir) {
let statObj = fs.statSync(dir);
if (statObj.isDirectory()) {
let dirs = fs.readdirSync(dir);
for(let i = 0; i < dirs.length; i++ ) {
rmDirDeepSync(path.join(dir, dirs[i]))
}
fs.rmdirSync(dir);
} else {
fs.unlinkSync(dir);
}
}
rmDirDeepSync('A');
广度优先删除目录
思路:如下图所示结构,广度优先遍历的思路是使用一个数组按照顺序存储所有的节点,然后使用一个指针,依次向后挪动,指针所指向的是目录的话,再次遍历出子节点,并拼接至数组。然后从后到前依次删除。
比如下图在数组中最终是这个样子的[ 'A', 'A/B', 'A/C', 'A/D', 'A/B/E', 'A/B/F' ]。
function rmDirWideSync(dir){
let arr = [dir]; // 存储数组
let index = 0; // 指针
let current; // 当前指针指向的元素
while(current = arr[index]) {
let statObj = fs.statSync(current);
if(statObj.isDirectory()){
let dirArr = fs.readdirSync(current).map(d => path.join(current, d));
arr = [...arr, ...dirArr];
}
index++;
}
for (let i = arr.length - 1; i >=0; i--) { // 倒序删除,先删除子级,再删除父级
let statObj = fs.statSync(arr[i]);
if(statObj.isDirectory()) {
fs.rmdirSync(arr[i]);
} else {
fs.unlinkSync(arr[i]);
}
}
}
rmDirWideSync('A');
总结:同步删除有广度优先和深度优先两种方案,异步删除也有两种方案,异步串行删除,和异步并行删除。
异步串行:(采用深度递归,深度优先方案)
function rmDirAsyncSerie(dir,cb) {
fs.stat(dir, (err, stats) => {
if(stats.isDirectory()) {
fs.readdir(dir, (err, dirs) => {
dirs = dirs.map((item) => {
return path.resolve(dir, item);
})
function next(index) {
if(index === dirs.length) {
fs.rmdir(dir, cb);
return;
}
rmDirAsyncSerie(dirs[index], () => {
next(++index);
});
}
next(0);
})
} else {
fs.unlink(dir, cb);
}
});
}
rmDirAsyncSerie('a', () => {
console.log('删除完成');
});
异步并行:异步的好处就是任务可以并行执行。
function rmDirAsyncParalle(dir, cb) {
fs.stat(dir, (err, stats) => {
if(stats.isDirectory()) {
fs.readdir(dir, (err, dirs) => {
if (dirs.length === 0) {
fs.rmdir(dir, cb);
return;
}
dirs.map((d) =>{
let current = path.join(dir, d);
rmDirAsyncParalle(current, done);
})
let index = 0;
function done() {
index++;
if(index === dirs.length) {
fs.rmdir(dir, cb);
}
}
})
}else{
fs.unlink(dir, cb);
}
})
}
rmDirAsyncParalle('a', () => {
console.log('删除成功');
})
并行删除效率会更高,并行和串行的区别就在于,并行是在循环中执行删除方法的,串行是执行完本次删除任务后,再去调用下一个删除方法的。
注意观察串行删除的next方法和并行删除的done方法。
网友评论