node中实现删除目录的几种方法


Posted in Javascript onJune 24, 2019

由于删除目录只能删除空目录(如果有子文件或文件夹要先删除)

目录结构算是典型的二叉树模型,所以涉及到遍历树结构

二叉树遍历(分为深度和广度,以及先序,中序,后序之分)

以下以深度先序解决目录删除

在node中由于主线程为单线程, 可以采取串行方式和并行方式

无论用什么方法删除,就一点核心: 如果是文件直接删除, 如果不是就删除所有子文件或子目录, 然后记得(一定记得删除自己)

深度先序(串行)

深度先序(串行 回调方式)

const fs = require('fs')
const path = require('path')
function rmdir(filePath, callback) {
  // 先判断当前filePath的类型(文件还是文件夹,如果是文件直接删除, 如果是文件夹, 去取当前文件夹下的内容, 拿到每一个递归)
  fs.stat(filePath, function(err, stat) {
    if(err) return console.log(err)
    if(stat.isFile()) {
      fs.unlink(filePath, callback)
    }else {
      fs.readdir(filePath, function(err, data) {
        if(err) return console.log(err)
        let dirs = data.map(dir => path.join(filePath, dir))
        let index = 0
        !(function next() {
          // 此处递归删除掉所有子文件 后删除当前 文件夹
          if(index === dirs.length) {
            fs.rmdir(filePath, callback)
          }else {
            rmdir(dirs[index++],next)
          }
        })()
      })
    }
  })
}

rmdir('a', function() {
  console.log('删除成功')
})

深度先序 (串行 promise写法)

const fs = require('fs')
const path = require('path')
function rmdirPromise(filePath) {
  return new Promise((resolve, reject) => {
    fs.stat(filePath, function(err, stat) {
      if(err) reject(err)
      if(stat.isFile()) {
        fs.unlink(filePath, function(err) {
          if(err) reject(err)
          resolve()
        })
      }else {
        fs.readdir(filePath, function(err, dirs) {
          if(err) reject(err)
          dirs = dirs.map(dir => path.join(filePath, dir)) // a/b a/c
          let index = 0;
          (function next() {
            if(index === dirs.length) {
              fs.rmdir(filePath, function(err) {
                if(err) reject(err)
                resolve()
              })
            }else {
              rmdirPromise(dirs[index++]).then(() => {
                next()
              }, err => {
                reject(err)
              })
            }
          })()
        })
      }
    })
  })
}

rmdirPromise('a').then(() => {
  console.log('删除成功')
})

深度先序 (串行 async await写法)

// 在node v10.0.0+版本中fs模块提供 promise 写法 const fs = require('fs').promises
// 如果在node 10之前的版本中可以引入第三方模块 mz const fs = require('mz/fs') 用法一致 https://www.npmjs.com/package/mz
const fs = require('fs').promises
const path = require('path')
async function rmdirAsync(filePath) {
  let stat = await fs.stat(filePath)
  if (stat.isFile()) {
    await fs.unlink(filePath)
  } else {
    let dirs = await fs.readdir(filePath)
    dirs = dirs.map(dir => path.join(filePath, dir))
    let index = 0;
    (async function next() {
      if (index === dirs.length) {
        await fs.rmdir(filePath)
      } else {
        await rmdirAsync(dirs[index++])
        await next()
      }
    })()
  }
}

rmdirAsync('a').then(() => {
  console.log('删除成功')
}, (err) => {
  console.log('err', err)
})

深度先序 (并行)

深度先序 (并行 回调写法)

const fs = require('fs').promises
const path = require('path')

function rmdir(filePath, callback) {
  fs.stat(filePath, function(err,stat) {
    if(err) return console.log(err)
    if(stat.isFile()) {
      fs.unlink(filePath, callback)
    }else {
      fs.readdir(filePath, function(err, dirs) {
        if(err) return console.log(err)
        // 此处要添加dirs.length的验证,不然如果length为0 后面的forEach不执行, 就删不掉当前目录了, 也执行不了callback
        if(dirs.length === 0) {
          fs.rmdir(filePath, callback)
        }
        dirs = dirs.map(dir => path.join(filePath, dir))
        // 通过计数的方式来判断是否子目录都删除了
        let index = 0
        function done() {
          if(++index === dirs.length) {
            fs.rmdir(filePath, callback)
          }
        }
        // 何为并行? a下有两个目录b, c,那么同时将b, c的删除都推到event Loop中,用for循环实现
        dirs.forEach(dir => {
          // 通过done回调的方式来控制js执行流程(LazyMan问题也是这么解决的)
          rmdir(dir, done)
        });
      })
    }
  })
}
rmdir('a', function() {
  console.log('删除成功')
})

深度先行 (并行promise写法)

const fs = reqire('fs')
const path = require('path')
function rmdirPromise(filePath) {
  return new Promise((resolve, reject) => {
    fs.stat(filePath, function (err, stat) {
      if (err) reject(err)
      if (stat.isFile()) {
        fs.unlink(filePath, function (err) {
          if (err) reject(err)
          resolve()
        })
      } else {
        fs.readdir(filePath, function (err, dirs) {
          if (err) reject(err)
          dirs = dirs.map(dir => path.join(filePath, dir))
          dirs = dirs.map(dir => rmdirPromise(dir))
          Promise.all(dirs).then(() => {
            fs.rmdir(filePath, resolve)
          })
        })
      }
    })
  })
}

rmdirPromise('a').then(() => {
  console.log('删除成功')
})

深度先序 (并行 async + await写法)

const fs = require('fs').promises
const path = require('path')
async function rmdirAsync(filePath) {
  let stat = await fs.stat(filePath)
  if(stat.isFile()) {
    await fs.unlink(filePath)
  }else {
    let dirs = await fs.readdir(filePath)
    dirs = dirs.map(dir => rmdirAsync(path.join(filePath, dir)))
    await Promise.all(dirs)
    await fs.rmdir(filePath)
  }
}

rmdirAsync('a').then(() => {
  console.log('删除成功')
})

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
出现“不能执行已释放的Script代码”错误的原因及解决办法
Aug 29 Javascript
快速解决jQuery与其他库冲突的方法介绍
Jan 02 Javascript
JQuery中两个ul标签的li互相移动实现方法
May 18 Javascript
深入理解JavaScript中Ajax
Aug 02 Javascript
JS读写CSS样式的方法汇总
Aug 16 Javascript
jQuery双向列表选择器select版
Nov 01 Javascript
AngularJS constant和value区别详解
Feb 28 Javascript
jquery mobile实现可折叠的导航按钮
Mar 11 Javascript
本地存储localStorage用法详解
Jul 31 Javascript
Vue2.X 通过AJAX动态更新数据
Jul 17 Javascript
Vue.js 实现数据展示全部和收起功能
Sep 05 Javascript
详解如何在微信小程序开发中正确的使用vant ui组件
Sep 13 Javascript
什么时候不能在 Node.js 中使用 Lock Files
Jun 24 #Javascript
vue-cli脚手架引入弹出层layer插件的几种方法
Jun 24 #Javascript
浅谈一个webpack构建速度优化误区
Jun 24 #Javascript
vue项目中运用webpack动态配置打包多种环境域名的方法
Jun 24 #Javascript
Vue.js+cube-ui(Scroll组件)实现类似头条效果的横向滚动导航条
Jun 24 #Javascript
JavaScript学习教程之cookie与webstorage
Jun 23 #Javascript
React组件对子组件children进行加强的方法
Jun 23 #Javascript
You might like
从零开始 教你如何搭建Discuz!4.1论坛
2006/07/07 PHP
深入解析yii权限分级式访问控制的实现(非RBAC法)
2013/06/13 PHP
Linux下PHP连接Oracle数据库
2014/08/20 PHP
PHP获取不了React Native Fecth参数的解决办法
2016/08/26 PHP
thinkPHP统计排行与分页显示功能示例
2016/12/02 PHP
mac os快速切换多个PHP版本的方法
2017/03/07 PHP
jQuery对表单元素的取值和赋值操作代码
2011/05/19 Javascript
js判断字符长度以及中英文数字等
2013/12/31 Javascript
jQuery对象初始化的传参方式
2015/02/26 Javascript
HTML5实现留言和回复页面样式
2015/07/22 Javascript
jQuery中的ajax async同步和异步详解
2015/09/29 Javascript
js密码强度实时检测代码
2016/03/02 Javascript
详解JavaScript的AngularJS框架中的表达式与指令
2016/03/05 Javascript
JavaScript 轮播图和自定义滚动条配合鼠标滚轮分享代码贴
2016/10/28 Javascript
jQuery webuploader分片上传大文件
2016/11/07 Javascript
vue获取DOM元素并设置属性的两种实现方法
2017/09/30 Javascript
vue-cli项目无法用本机IP访问的解决方法
2018/09/20 Javascript
VUE实现密码验证与提示功能
2019/10/18 Javascript
小程序点击图片实现png转jpg
2019/10/22 Javascript
layui前端时间戳转化实例
2019/11/15 Javascript
浅谈Vue使用Cascader级联选择器数据回显中的坑
2020/10/31 Javascript
Python实现二叉堆
2016/02/03 Python
python+selenium+autoit实现文件上传功能
2017/08/23 Python
python opencv实现旋转矩形框裁减功能
2018/07/25 Python
Python get获取页面cookie代码实例
2018/09/12 Python
用python爬取租房网站信息的代码
2018/12/14 Python
Python中字符串List按照长度排序
2019/07/01 Python
pycharm中如何自定义设置通过“ctrl+滚轮”进行放大和缩小实现方法
2020/09/16 Python
浅谈Python __init__.py的作用
2020/10/28 Python
HTML5 解决苹果手机不能自动播放音乐问题
2017/12/27 HTML / CSS
ONLY瑞典官网:世界知名服装品牌
2018/06/19 全球购物
英国家居用品和床上用品零售商:P&B Home
2020/01/16 全球购物
日语求职信范文
2013/12/17 职场文书
商铺门前三包责任书
2014/07/25 职场文书
2014年销售部工作总结
2014/12/01 职场文书
收音机爱好者玩机13年,简评其使用过的19台收音机
2022/04/30 无线电