node.js rmdir 是递归的吗?它可以在非空目录上工作吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12627586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:22:30  来源:igfitidea点击:

Is node.js rmdir recursive ? Will it work on non empty directories?

node.js

提问by Samuel Rossille

The documentation for fs.rmdiris very short and doesn't explain the behavior of rmdir when the directory is not empty.

fs.rmdir的文档非常简短,并且没有解释当目录不为空时 rmdir 的行为。

Q: What happens if I try to use this API to delete a non empty directory ?

:如果我尝试使用此 API 删除非空目录会怎样?

采纳答案by Henk Langeveld

Short answer: node.jsfs.rmdir()calls the POSIX rmdir(); this will remove an empty directory, or return an error. In the given case, the call will invoke the callback function and pass the error as an exception.

简短回答:node.jsfs.rmdir()调用 POSIX rmdir();这将删除一个空目录,或者返回一个错误。在给定的情况下,调用将调用回调函数并将错误作为异常传递。

The problem here is that the node.js documentation refers to POSIX:

这里的问题是 node.js 文档是指POSIX

The Node.js API DocsFile Systemintro says:

Node.js的API文档文件系统介绍说:

File I/O is provided by simple wrappers around standard POSIX functions.

文件 I/O 由围绕标准 POSIX 函数的简单包装器提供。

This almost changes the question into a duplicate of: Is there a listing of the POSIX API / functions?

这几乎将问题变成了重复: 是否有 POSIX API / 函数的列表?

The description for fs.rmdiris terse, but sufficient.

的描述fs.rmdir很简洁,但足够了。

Asynchronous rmdir(2).

异步 rmdir(2)。

The rmdir(2)here is an implicit reference to the documentation for the rmdir() system call. The number (2) here is an old unix man page convention to indicate Section 2 of the Manual pages, containing the kernel interfaces.

rmdir(2)这里是为文档的隐式引用rmdir() system call。此处的数字 (2) 是旧的 unix 手册页约定,表示手册页的第 2 节,其中包含内核接口。

回答by Besi

Although using a third-party library for such a thing I could not come up with a more elegant solution. So I ended up using the npm-module rimraf.

虽然使用第三方库来做这样的事情,但我想不出更优雅的解决方案。所以我最终使用了 npm-module rimraf

Install it

安装它

npm install rimraf

Or install it and save to 'package.json' (other save options can be found in the npm-installdocs)

或者安装它并保存到“package.json”(其他保存选项可以在npm-install文档中找到)

npm install --save rimraf

Then you can do the following:

然后您可以执行以下操作:

rmdir = require('rimraf');
rmdir('some/directory/with/files', function(error){});

Or in Coffeescript:

或者在 Coffeescript 中:

rmdir = require 'rimraf'
rmdir 'some/directory/with/files', (error)->

回答by geedew

I wrote about this problem exactly.

我写的正是这个问题

My previous solution below, while simple, is not preferred. The following function, is a Synchronous solution; while async might be preferred.

我之前的解决方案虽然简单,但不是首选。下面的函数,是一个同步解决方案;而异步可能是首选。

deleteFolderRecursive = function(path) {
    var files = [];
    if( fs.existsSync(path) ) {
        files = fs.readdirSync(path);
        files.forEach(function(file,index){
            var curPath = path + "/" + file;
            if(fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
};

[Edit]Added lstat instead of stat to prevent errors on symlinks

[编辑]添加了 lstat 而不是 stat 以防止符号链接错误

[Previous Solution]

[以前的解决方案]

My solution to this is quite easy to implement.

我对此的解决方案很容易实现。

var exec = require('child_process').exec,child;
child = exec('rm -rf test',function(err,out) { 
  console.log(out); err && console.log(err); 
});

This is slimmed down for this page, but the basic idea is simple; execute 'rm -r' on the command line. If your app needs to run across different types of OS, put this in a function and have an if/else/switch to handle it.

这个页面已经精简了,但基本思想很简单;在命令行上执行“rm -r”。如果您的应用程序需要在不同类型的操作系统上运行,请将其放在一个函数中并使用 if/else/switch 来处理它。

You will want to handle all the responses; but the idea is simple enough.

您将需要处理所有响应;但这个想法很简单。

回答by kimamula

Node.js v12.10.0 introduced recursiveoption into fs.rmdir. As fs.mkdirsupports the same option since v10.12.0, both making and removing directory can be executed recursively.

Node.js v12.10.0recursivefs.rmdir. 由于fs.mkdir从 v10.12.0 开始支持相同的选项,创建和删除目录都可以递归执行。

$ node --experimental-repl-await

# without recursive option -> error
> await fs.promises.mkdir('foo/bar')
Thrown:
[Error: ENOENT: no such file or directory, mkdir 'foo/bar'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'mkdir',
  path: 'foo/bar'
}

# with recursive option -> success
> await fs.promises.mkdir('foo/bar', { recursive: true })
undefined

# without recursive option -> error
> await fs.promises.rmdir('foo')
Thrown:
[Error: ENOTEMPTY: directory not empty, rmdir 'foo'] {
  errno: -66,
  code: 'ENOTEMPTY',
  syscall: 'rmdir',
  path: 'foo'
}

# with recursive option -> success
> await fs.promises.rmdir('foo', { recursive: true })
undefined

回答by reallynice

Just a small dot among this bunch of answers, but I think it's good to point it out.

这只是一堆答案中的一个小点,但我认为指出这一点很好。

Personally (and generally) I would prefer to use an already existing library, if there's one available, for doing the task. Taking an already existing thing means, for me and especially in the open source world, using and improving an already existing thing, which could end up in a better result than doing it on my own (I'm improving something that some one other has done).

就个人而言(并且一般而言),我更愿意使用已经存在的库(如果有可用的库)来完成任务。对我来说,特别是在开源世界中,使用一个已经存在的东西意味着使用和改进一个已经存在的东西,这可能会比我自己做得到更好的结果(我正在改进其他人已经拥有的东西)完毕)。

In this case, with a small search I found out the module fs-extra, which aims to be a replacement also for rimrafand answers to the need to remove recursively directories (apparently with async and sync versions). Furthermore, it has got a good number of stars on github and seems currently mantained: these two conditions, in addition to the fact that answers to the need, make it the way to go (almosto for a bit) for me.

在这种情况下,通过一个小的搜索,我发现了模块 fs-extra,它旨在替代rimraf和解决递归删除目录(显然是异步和同步版本)的需要。此外,它在 github 上获得了很多星星,并且目前似乎得到了维护:这两个条件,除了满足需求的事实外,使它成为我要走的路(几乎有点)。

回答by Thorsten Lorenz

fs.rmdiris notrecursive.

fs.rmdir不是递归的。

You could instead use a recursive fs.readdir module like readdirpin order to find all files and directories . Then remove all files, followed by all directories.

您可以改为使用递归 fs.readdir 模块(如readdirp)来查找所有文件和目录。然后删除所有文件,然后删除所有目录。

For an even simpler solution have a look at rimraf.

对于更简单的解决方案,请查看rimraf

回答by zupa

Use child_process.execFile it is faster.

使用 child_process.execFile 它更快

NodeJS docs:

NodeJS 文档:

child_process.execFile is similar to child_process.exec() except it* does not execute a subshell but rather the specified file directly.

child_process.execFile 与 child_process.exec() 类似,只是它* 不执行子shell 而是直接执行指定的文件。

This works.Mimicking rm -rf DIR...

这有效。模仿rm -rf DIR...

var child = require('child_process');

var rmdir = function(directories, callback) {
    if(typeof directories === 'string') {
        directories = [directories];
    }
    var args = directories;
    args.unshift('-rf');
    child.execFile('rm', args, {env:process.env}, function(err, stdout, stderr) {
            callback.apply(this, arguments);
    });
};

// USAGE
rmdir('dir');
rmdir('./dir');
rmdir('dir/*');
rmdir(['dir1', 'dir2']);

Edit: I have to admit this is not cross-platform, will not work on Windows

编辑:我不得不承认这不是跨平台的,不能在 Windows 上工作

回答by kliron

Here is an asynchronous recursive version that works with promises. I use the 'Q' library but anyone will do with a few changes (eg the 'fail' function).

这是一个适用于 Promise 的异步递归版本。我使用“Q”库,但任何人都会做一些更改(例如“失败”功能)。

To make use of it, we must make a few simple wrappers around some core Node functions, namely fs.stat, fs.readdir, fs.unlink and fs.rmdir to make them promise-friendly.

为了使用它,我们必须对一些核心 Node 函数做一些简单的包装,即 fs.stat、fs.readdir、fs.unlink 和 fs.rmdir,使它们对 promise 友好。

Here they are:

他们来了:

function getStat(fpath) {
  var def = Q.defer();
  fs.stat(fpath, function(e, stat)?{
    if (e) { def.reject(); } else { def.resolve(stat); }
  });
  return def.promise;
}

function readdir(dirpath) {
  var def = Q.defer();
  fs.readdir(dirpath, function(e, files) {
    if (e) { def.reject(e); } else { def.resolve(files); }
  });
  return def.promise;
}

function rmFile(fpath) {
  var def = Q.defer();
  fs.unlink(fpath, function(e) { if(e) { def.reject(e); } else { def.resolve(fpath); }});
  return def.promise;
}

function rmDir(fpath) {
  var def = Q.defer(); 
  fs.rmdir(fpath, function(e) { if(e)?{ def.reject(e); } else { def.resolve(fpath); }});
  return def.promise;
}

So here is the recursive rm function:

所以这里是递归 rm 函数:

var path = require('path');

function recursiveDelete(fpath) {
  var def = Q.defer();

  getStat(fpath)
  .then(function(stat)?{
    if (stat.isDirectory())?{
      return readdir(fpath)
      .then(function(files) {
        if (!files.length) { 
          return rmDir(fpath);
        } else {
          return Q.all(files.map(function(f) { return recursiveDelete(path.join(fpath, f)); }))
          .then(function() {?return rmDir(fpath); });
        }
      }); 
    } else {
      return rmFile(fpath);
    }
  })
  .then(function(res) { def.resolve(res); })
  .fail(function(e) { def.reject(e); })
  .done();
  return def.promise;
}

回答by gustaf r

In addition to the correct "no" answers, the rimrafpackage provides recursive delete functionality. It mimics rm -rf. It's also officially packagedby Ubuntu.

除了正确的“否”答案外,rimraf包还提供递归删除功能。它模仿rm -rf. 它也由 Ubuntu正式打包

回答by mike

Figured this was a good excuse to take a dive into the source ;)

认为这是深入了解源代码的好借口;)

From what I can tell, fs.rmdiris bound to the rmdir function from unistd.h. From the POSIX man page for rmdir:

据我所知,fs.rmdir绑定到 unistd.h 中的 rmdir 函数。从rmdirPOSIX 手册页

The rmdir() function shall remove a directory whose name is given by path. The directory shall be removed only if it is an empty directory.

If the directory is not an empty directory, rmdir() shall fail and set errno to [EEXIST] or [ENOTEMPTY].

rmdir() 函数将删除一个由路径指定名称的目录。仅当目录为空目录时才应删除该目录。

如果目录不是空目录,则 rmdir() 将失败并将 errno 设置为 [EEXIST] 或 [ENOTEMPTY]。