使用node中fs模組建立和刪除資料夾

romin發表於2018-03-23

建立資料夾

假如我們要建立這樣一個資料夾‘a/d/c/d/e’

使用node中fs模組建立和刪除資料夾

同步建立資料夾

let fs = require('fs');
function makep(dir) {
  let paths = dir.split('/');
  for(let i =1;i<paths.length;i++){
    let newPath = paths.slice(0,i).join('/');
    try{
    //是否能訪問到這個檔案,如果能訪問到,說明這個檔案已經存在,進入迴圈的下一步。
    //accessSync的第二個引數就是用來判斷該檔案是否能被讀取
      fs.accessSync(newPath,fs.constants.R_OK);
      
    }catch (e){
      fs.mkdirSync(newPath);
    }
  }
}
makep('a/d/c/d/e')
複製程式碼

同步建立會有效能的問題,所以這種建立方式是不推薦的,我們最好用非同步建立

非同步建立資料夾

我們使用遞迴來建立資料夾

function mkdirSync(dir,cb) {
  let paths = dir.split('/');
  let index  =1;
  function next(index) {
  //遞迴結束判斷
    if(index>paths.length)return cb();
    let newPath = paths.slice(0,index).join('/');
    fs.access(newPath,function (err) {
      if(err){//如果檔案不存在,就建立這個檔案
        fs.mkdir(newPath,function (err) {
          next(index+1);
        });
      }else{
      //如果這個檔案已經存在,就進入下一個迴圈
        next(index+1);
      }
    })
  }
  next(index);
}
mkdirSync('a/b/c/d/e',function () {
  console.log('建立成功')
})
複製程式碼

刪除資料夾

首先,我們必須先判斷該檔案是否為非空檔案;如果是空檔案就刪除,如果不是空,那麼先刪除子檔案,直到父級檔案為空,再刪父級檔案。

同步刪除資料夾

function removeDir(dir) {
  let files = fs.readdirSync(dir)
  for(var i=0;i<files.length;i++){
    let newPath = path.join(dir,files[i]);
    let stat = fs.statSync(newPath)
    if(stat.isDirectory()){
      //如果是資料夾就遞迴下去
      removeDir(newPath);
    }else {
     //刪除檔案
      fs.unlinkSync(newPath);
    }
  }
  fs.rmdirSync(dir)//如果資料夾是空的,就將自己刪除掉
}
removeDir('a');
複製程式碼

非同步刪除資料夾

promise版

function removePromise(dir) {
  return new Promise(function (resolve, reject) {
    //先讀資料夾
    fs.stat(dir,function (err, stat) {
      if(stat.isDirectory()){
        fs.readdir(dir,function (err, files) {
          files = files.map(file=>path.join(dir,file)); // a/b  a/m
          files = files.map(file=>removePromise(file)); //這時候變成了promise
          Promise.all(files).then(function () {
            fs.rmdir(dir,resolve);
          })
        })
      }else {
        fs.unlink(dir,resolve)
      }
    })

  })
}
removePromise('a').then(function () {
  console.log('刪除成功')
})
複製程式碼

非同步刪除-深度優先遍歷

使用node中fs模組建立和刪除資料夾
深度優先的主要思想就是“不撞南牆不回頭”,“一條路走到黑”,如果遇到“牆”或者“無路可走”時再去走下一條路。所以檔案的刪除順序就是

4->5->3->6->2->7->10->11->9->12->8->1

我們用程式碼來實現

let fs = require('fs');
let path = require('path');
function rmdir(dir,cb) {
  fs.readdir(dir,function (err, files) {
    next(0);
    function next(index) {
      if(index == files.length)
        return fs.rmdir(dir,cb);
      let newPath = path.join(dir,files[index]);
      console.log(newPath)
      fs.stat(newPath,function (err, stat) {
        if(err){
          console.log(err);
        }
        if(stat.isDirectory()){
          // 在這裡完成深度優先,一層層往下找,直到找到非空資料夾
          rmdir(newPath,()=>next(index+1));
        }else {
        // 刪除檔案
          fs.unlink(newPath,function (err) {
                            if (err) {
                                console.error(err);
                            }
                            next(index + 1);
                        });
        }
      })
    }
  })
}
rmdir('a',function () {
  console.log('刪除成功')
});
複製程式碼

非同步刪除-廣度優先

廣度優先就是從根節點開始,沿著樹的寬度遍歷樹的節點,如果發現目標,則演算終止

圖片

廣度優先搜尋演算法的動畫範例

let fs = require('fs');
let path = require('path');
function wide(dir,cb){
  let arrs = [dir];
  let index = 0;
  function rmdir() {
    console.log(arrs)
    let current = arrs[--index];
    if (current) {
      fs.stat(current, (err, stat) => {
        if (stat.isDirectory()) {
          fs.rmdir(current, rmdir);
        } else {
          fs.unlink(current, rmdir)
        }
      })
    }
  }

  !function next(){
    if(index === arrs.length) {return rmdir();}
    let current = arrs[index++];
    fs.stat(current,function(err,stat){
      if(stat.isDirectory()){
        fs.readdir(current,function(err,files){
          arrs = [...arrs,...files.map(file=>
            path.join(current,file);
          })]; // ['a','a/b','a/c','a/b/d','a/c/e'];
          next();
        });
      }else{
        next();
      }
    })
  }()
}
wide('a',function () {
  console.log('刪除成功')
});

複製程式碼

結語

上面的函式中大量使用到遞迴,如果對遞迴不太瞭解的話,理解起來會吃力一些。

相關文章