在我的节点应用程序中,我需要删除一个目录,其中有一些文件,但fs。Rmdir只适用于空目录。我该怎么做呢?


当前回答

从Node.js 14.14.0开始,推荐使用fs.rmSync:

fs.rmSync(dir, { recursive: true, force: true });

其他回答

而递归是fs.rmdir的一个实验性选项

function rm (path, cb) {
    fs.stat(path, function (err, stats) {
        if (err)
            return cb(err);

        if (stats.isFile())
            return fs.unlink(path, cb);

        fs.rmdir(path, function (err) {
            if (!err || err && err.code != 'ENOTEMPTY') 
                return cb(err);

            fs.readdir(path, function (err, files) {
                if (err)
                    return cb(err);

                let next = i => i == files.length ? 
                    rm(path, cb) : 
                    rm(path + '/' + files[i], err => err ? cb(err) : next(i + 1));

                next(0);
            });
        });
    });
}

截至节点v14(2020年10月),fs模块有fs。rm和rs.rmSync支持递归非空目录解链接:

https://nodejs.org/docs/latest-v14.x/api/fs.html#fs_fs_rm_path_options_callback

所以你现在可以这样做:

const fs = require('fs');
fs.rm('/path/to/delete', { recursive: true }, () => console.log('done'));

or:

const fs = require('fs');
fs.rmSync('/path/to/delete', { recursive: true });
console.log('done');

事实上的包是rimraf,但这里是我的小异步版本:

const fs = require('fs')
const path = require('path')
const Q = require('q')

function rmdir (dir) {
  return Q.nfcall(fs.access, dir, fs.constants.W_OK)
    .then(() => {
      return Q.nfcall(fs.readdir, dir)
        .then(files => files.reduce((pre, f) => pre.then(() => {
          var sub = path.join(dir, f)
          return Q.nfcall(fs.lstat, sub).then(stat => {
            if (stat.isDirectory()) return rmdir(sub)
            return Q.nfcall(fs.unlink, sub)
          })
        }), Q()))
    })
    .then(() => Q.nfcall(fs.rmdir, dir))
}

方法删除非空目录

rmdir(path,{recursive:true,force:true}
rm(path,{recursive:true,force:true}

将工作

代码片段:

const fsp = require("fs/promises");

deleteDirRecursively("./b");
removeRecursively("./BCD/b+");

async function deleteDirRecursively(dirPath) {
  try {
    // fsPromises.rmdir() on a file (not a directory) results in the promise being rejected
    // with an ENOENT error on Windows and an ENOTDIR error on POSIX.
    // To get a behavior similar to the rm -rf Unix command,
    // use fsPromises.rm() with options { recursive: true, force: true }.
    //will not thorw error if dir is empty
    //will thow error if dir is not present
    await fsp.rmdir(dirPath, { recursive: true, force: true });
    console.log(dirPath, "deleted successfully");
  } catch (err) {
    console.log(err);
  }

async function removeRecursively(path) {
  try {
    //has ability to remove both file and dir
    //can delete dir recursively and forcefully
    //will delete an empty dir.
    //will remove all the contents of a dir.
    // the only difference between rmdir and rm is that rmdir can only delete dir's
    await fsp.rm(path, { recursive: true, force: true });
    console.log(path, "deleted successfully");
  } catch (err) {
    console.log(err);
  }
}

如果你正在使用的节点8+想要异步,不想要外部依赖,这里是async/await版本:

const path = require('path');
const fs = require('fs');
const util = require('util');

const readdir = util.promisify(fs.readdir);
const lstat = util.promisify(fs.lstat);
const unlink = util.promisify(fs.unlink);
const rmdir = util.promisify(fs.rmdir);

const removeDir = async (dir) => {
    try {
        const files = await readdir(dir);
        await Promise.all(files.map(async (file) => {
            try {
                const p = path.join(dir, file);
                const stat = await lstat(p);
                if (stat.isDirectory()) {
                    await removeDir(p);
                } else {
                    await unlink(p);
                    console.log(`Removed file ${p}`);
                }
            } catch (err) {
                console.error(err);
            }
        }))
        await rmdir(dir);
        console.log(`Removed dir ${dir}`);
    } catch (err) {
      console.error(err);
    }
}