在我的Node应用程序中,我需要删除一个包含某些文件的目录,但fs.rmdir
仅适用于空目录。我怎么能这样做?
答案 0 :(得分:230)
有一个名为rimraf
(https://npmjs.org/package/rimraf)的模块。它提供与rm -Rf
异步用法:
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
同步用法:
rimraf.sync("/some/directory");
答案 1 :(得分:125)
大多数使用fs
和Node.js的人都希望函数接近" Unix方式"处理文件。我使用fs-extra带来了所有很酷的东西:
fs-extra包含未包含在vanilla Node.js中的方法 fs包。例如mkdir -p,cp -r和rm -rf。
更好的是, fs-extra 是原生fs的替代品。 fs中的所有方法都是未修改的并附加到它上面。 这意味着您可以通过 fs-extra :
替换fs// this can be replaced
const fs = require('fs')
// by this
const fs = require('fs-extra')
然后您可以通过这种方式删除文件夹:
fs.removeSync('/tmp/myFolder');
//or
fs.remove('/tmp/myFolder', callback);
答案 2 :(得分:46)
使用Node.js 12.10,您最终可以做一个简单的事情:
fs.rmdir(dir, { recursive: true });
recursive
选项会递归删除整个内容。
答案 3 :(得分:19)
自 Node 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'));
或:
const fs = require('fs');
fs.rmSync('/path/to/delete', { recursive: true });
console.log('done');
答案 4 :(得分:18)
我从@oconnecp(https://stackoverflow.com/a/25069828/3027390)
修改了答案使用path.join获得更好的跨平台体验。 所以,不要忘记要求它。
var path = require('path');
还将功能重命名为rimraf
;)
/**
* Remove directory recursively
* @param {string} dir_path
* @see https://stackoverflow.com/a/42505874/3027390
*/
function rimraf(dir_path) {
if (fs.existsSync(dir_path)) {
fs.readdirSync(dir_path).forEach(function(entry) {
var entry_path = path.join(dir_path, entry);
if (fs.lstatSync(entry_path).isDirectory()) {
rimraf(entry_path);
} else {
fs.unlinkSync(entry_path);
}
});
fs.rmdirSync(dir_path);
}
}
答案 5 :(得分:10)
const fs = require('fs');
const path = require('path');
function deleteFile(dir, file) {
return new Promise(function (resolve, reject) {
var filePath = path.join(dir, file);
fs.lstat(filePath, function (err, stats) {
if (err) {
return reject(err);
}
if (stats.isDirectory()) {
resolve(deleteDirectory(filePath));
} else {
fs.unlink(filePath, function (err) {
if (err) {
return reject(err);
}
resolve();
});
}
});
});
};
function deleteDirectory(dir) {
return new Promise(function (resolve, reject) {
fs.access(dir, function (err) {
if (err) {
return reject(err);
}
fs.readdir(dir, function (err, files) {
if (err) {
return reject(err);
}
Promise.all(files.map(function (file) {
return deleteFile(dir, file);
})).then(function () {
fs.rmdir(dir, function (err) {
if (err) {
return reject(err);
}
resolve();
});
}).catch(reject);
});
});
});
};
答案 6 :(得分:9)
我写了这个名为remove folder的函数。它将递归删除某个位置中的所有文件和文件夹。它需要的唯一包是异步。
var async = require('async');
function removeFolder(location, next) {
fs.readdir(location, function (err, files) {
async.each(files, function (file, cb) {
file = location + '/' + file
fs.stat(file, function (err, stat) {
if (err) {
return cb(err);
}
if (stat.isDirectory()) {
removeFolder(file, cb);
} else {
fs.unlink(file, function (err) {
if (err) {
return cb(err);
}
return cb();
})
}
})
}, function (err) {
if (err) return next(err)
fs.rmdir(location, function (err) {
return next(err)
})
})
})
}
答案 7 :(得分:8)
[编辑:使用 node.js v15.5.0]
刚刚尝试使用这里发布的一些解决方案,我遇到了以下弃用警告:
<块引用>(node:13202) [DEP0147] DeprecationWarning:在未来的版本中 Node.js, fs.rmdir(path, { recursive: true }) 如果 path 会抛出 不存在或者是一个文件。使用 fs.rm(path, { recursive: true, force: true }) 代替
fs.rm(path, { recursive: true, force: true });
效果很好,如果您想使用阻止版本,请使用 fs.rmSync(path, { recursive: true, force: true });
。
答案 8 :(得分:6)
如果您正在使用节点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);
}
}
答案 9 :(得分:6)
const fs = require("fs");
fs.rmdir("./test", { recursive: true }, (err) => {
if (err) {
console.error(err);
}
});
提供recursive: true
选项。并且它将递归删除给定路径的所有文件和目录。 (假设test
是根目录。)
答案 10 :(得分:3)
我试图通过gulp
来到这里,并且我正在为更远的距离写作。
gulp-clean
已弃用gulp-rimraf
gulp-rimraf
弃用赞成delete-files-folders
如果要使用del
删除文件和文件夹,则应附加/**
以进行递归删除。
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
答案 11 :(得分:3)
根据fs
documentation,fsPromises
当前在实验的基础上提供了recursive
选项,至少就我个人而言,在Windows上,它会删除目录及其中的任何文件。
fsPromises.rmdir(path, {
recursive: true
})
recursive: true
是否在Linux和MacOS上删除文件?
答案 12 :(得分:2)
在最新版本的Node.js(12.10.0或更高版本)中,rmdir
样式函数fs.rmdir()
,fs.rmdirSync()
和fs.promises.rmdir()
具有新的实验选项recursive
允许删除非空目录,例如
fs.rmdir(path, { recursive: true });
GitHub上的相关PR:https://github.com/nodejs/node/pull/29168
答案 13 :(得分:2)
使用fs.promises的@SharpCoder异步版本:
const afs = fs.promises;
const deleteFolderRecursive = async path => {
if (fs.existsSync(path)) {
for (let entry of await afs.readdir(path)) {
const curPath = path + "/" + entry;
if ((await afs.lstat(curPath)).isDirectory())
await deleteFolderRecursive(curPath);
else await afs.unlink(curPath);
}
await afs.rmdir(path);
}
};
答案 14 :(得分:2)
我希望有一种方法可以做到这一点,没有额外的模块,这些东西是如此微不足道和常见,但这是我能想到的最好的。
更新: 现在应该可以在Windows上运行(经过测试的Windows 10),也可以在Linux / Unix / BSD / Mac系统上运行。
const
execSync = require("child_process").execSync,
fs = require("fs"),
os = require("os");
let removeDirCmd, theDir;
removeDirCmd = os.platform() === 'win32' ? "rmdir /s /q " : "rm -rf ";
theDir = __dirname + "/../web-ui/css/";
// WARNING: Do not specify a single file as the windows rmdir command will error.
if (fs.existsSync(theDir)) {
console.log(' removing the ' + theDir + ' directory.');
execSync(removeDirCmd + '"' + theDir + '"', function (err) {
console.log(err);
});
}
答案 15 :(得分:1)
2020更新
从版本12.10.0开始,为选项添加了 recursiveOption 。
请注意,递归删除是实验性的。
所以您要进行同步:
fs.rmdirSync(dir, {recursive: true});
或异步:
fs.rmdir(dir, {recursive: true});
答案 16 :(得分:1)
return new Promise((resolve, reject) => {
const fs = require("fs");
// directory path
const dir = "your/dir";
// delete directory recursively <------
fs.rmdir(dir, { recursive: true }, (err) => {
if (err) {
reject(err);
}
resolve(`${dir} is deleted!`);
});
});
答案 17 :(得分:1)
static void ProcessAnswer(string[] array)
{
string action = array.GetValue(0).ToString();
value = array.GetValue(1).ToString();
string c = keyaction[action](); // calling the referenced funtion
Console.Write(c);
}
是recursive
的实验选项
fs.rmdir
答案 18 :(得分:1)
超速和防故障
您可以使用lignator
程序包(https://www.npmjs.com/package/lignator),它比任何异步代码(例如rimraf)都要快,并且具有更高的防故障能力(尤其是在Windows中,文件删除不是立即进行的,并且文件可能被其他进程锁定)。
在Windows上的 15秒内删除了4,36 GB的数据,28,042个文件,4,217个文件夹,而旧硬盘上rimraf的数据是60秒。
const lignator = require('lignator');
lignator.remove('./build/');
答案 19 :(得分:1)
使用文件或仅删除文件的同步文件夹。
我既不是献礼者,也不是贡献者,但是我找不到解决这个问题的好方法,所以我不得不找到办法...所以我希望您会喜欢:)
对于任何数量的嵌套目录和子目录,它都非常适合我。递归函数时,请注意“ this”的范围,您的实现可能有所不同。就我而言,此函数一直停留在另一个函数的返回中,这就是为什么我以此来调用它。
const fs = require('fs');
deleteFileOrDir(path, pathTemp = false){
if (fs.existsSync(path)) {
if (fs.lstatSync(path).isDirectory()) {
var files = fs.readdirSync(path);
if (!files.length) return fs.rmdirSync(path);
for (var file in files) {
var currentPath = path + "/" + files[file];
if (!fs.existsSync(currentPath)) continue;
if (fs.lstatSync(currentPath).isFile()) {
fs.unlinkSync(currentPath);
continue;
}
if (fs.lstatSync(currentPath).isDirectory() && !fs.readdirSync(currentPath).length) {
fs.rmdirSync(currentPath);
} else {
this.deleteFileOrDir(currentPath, path);
}
}
this.deleteFileOrDir(path);
} else {
fs.unlinkSync(path);
}
}
if (pathTemp) this.deleteFileOrDir(pathTemp);
}
答案 20 :(得分:1)
我通常不复活旧线程,但是这里有一个 lot ,而且没有rimraf回答,这些对我来说似乎都太复杂了。
首先在现代Node(> = v8.0.0)中,您可以仅使用节点核心模块,完全异步并以五行功能同时并行化文件的取消链接并行化,并且仍然保持可读性:
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const readdir = promisify(fs.readdir);
const rmdir = promisify(fs.rmdir);
const unlink = promisify(fs.unlink);
exports.rmdirs = async function rmdirs(dir) {
let entries = await readdir(dir, { withFileTypes: true });
return Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
return entry.isDirectory ? rmdir(fullPath) : unlink(fullPath);
}));
};
另一方面,path traversal attacks的警卫不适用于此功能,因为
rm -rf
类似,它接受一个参数,并允许用户rm -rf /
进行输入。脚本的职责是不要保护rm
程序本身。.isDirectory
是false
,并且未链接也不会出现。最后但并非最不重要的一点是,有一种罕见的竞争条件,如果在运行此递归的恰好时间,在此脚本的 outside 中取消链接或删除其中一个条目,则递归可能会出错。由于这种情况在大多数环境中并不常见,因此很可能会被忽略。但是,如果需要(对于某些极端情况),可以使用以下稍微复杂一些的示例来缓解此问题:
exports.rmdirs = async function rmdirs(dir) {
let entries = await readdir(dir, { withFileTypes: true });
let results = Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
let task = entry.isDirectory ? rmdir(fullPath) : unlink(fullPath);
return task.catch(error => ({ error }));
}));
results.forEach(result => {
// Ignore missing files/directories; bail on other errors
if (result && result.error.code !== 'ENOENT') throw result.error;
});
};
答案 21 :(得分:1)
Promisified version:
const fs = require('fs')
const path = require('path')
const Q = require('q')
function rmdir(dir) {
return Q.nfcall(fs.access, dir).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()))
}, err => {})
.then(() => Q.nfcall(fs.rmdir, dir))
}
答案 22 :(得分:0)
///不使用任何第三方库
const fs = require('fs');
var FOLDER_PATH = "./dirname";
var files = fs.readdirSync(FOLDER_PATH);
files.forEach(element => {
fs.unlinkSync(FOLDER_PATH + "/" + element);
});
fs.rmdirSync(FOLDER_PATH);
答案 23 :(得分:0)
这是一种使用promisify和两个帮助功能(to和toAll)来解决诺言的方法。
它会执行所有意外动作。
const fs = require('fs');
const { promisify } = require('util');
const to = require('./to');
const toAll = require('./toAll');
const readDirAsync = promisify(fs.readdir);
const rmDirAsync = promisify(fs.rmdir);
const unlinkAsync = promisify(fs.unlink);
/**
* @author Aécio Levy
* @function removeDirWithFiles
* @usage: remove dir with files
* @param {String} path
*/
const removeDirWithFiles = async path => {
try {
const file = readDirAsync(path);
const [error, files] = await to(file);
if (error) {
throw new Error(error)
}
const arrayUnlink = files.map((fileName) => {
return unlinkAsync(`${path}/${fileName}`);
});
const [errorUnlink, filesUnlink] = await toAll(arrayUnlink);
if (errorUnlink) {
throw new Error(errorUnlink);
}
const deleteDir = rmDirAsync(path);
const [errorDelete, result] = await to(deleteDir);
if (errorDelete) {
throw new Error(errorDelete);
}
} catch (err) {
console.log(err)
}
};
答案 24 :(得分:0)
安装
npm i graph-fs
使用
const {Node} = require("graph-fs");
const directory = new Node("/path/to/directory");
directory.delete(); // <--
答案 25 :(得分:0)
const fs = require("fs")
const path = require("path")
let _dirloc = '<path_do_the_directory>'
if (fs.existsSync(_dirloc)) {
fs.readdir(path, (err, files) => {
if (!err) {
for (let file of files) {
// Delete each file
fs.unlinkSync(path.join(_dirloc, file))
}
}
})
// After the 'done' of each file delete,
// Delete the directory itself.
if (fs.unlinkSync(_dirloc)) {
console.log('Directory has been deleted!')
}
}
答案 26 :(得分:0)
快速而肮脏的方式(可能用于测试)可能是直接使用exec
或spawn
方法来调用OS调用来删除目录。详细了解NodeJs child_process。
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
缺点是:
<强>优点:强>
答案 27 :(得分:0)
2020年答案
如果要在 npm脚本中执行此操作,则使用命令npx
例如,如果您要在运行npm run clean
时删除文件夹 dist 和 .cache ,则只需将此命令添加到软件包中.json
{
"scripts": {
"clean": "npx rimraf dist .cache"
}
}
它将在任何操作系统中工作
答案 28 :(得分:0)
另一种选择是使用提供fs-promise
模块的有希望版本的fs-extra
模块
然后你可以这样写:
const { remove, mkdirp, writeFile, readFile } = require('fs-promise')
const { join, dirname } = require('path')
async function createAndRemove() {
const content = 'Hello World!'
const root = join(__dirname, 'foo')
const file = join(root, 'bar', 'baz', 'hello.txt')
await mkdirp(dirname(file))
await writeFile(file, content)
console.log(await readFile(file, 'utf-8'))
await remove(join(__dirname, 'foo'))
}
createAndRemove().catch(console.error)
注意:async / await需要最近的nodejs版本(7.6 +)
答案 29 :(得分:0)
从 Node.js v14 开始,我们现在可以使用 require("fs").promises.rm
函数通过 promise 删除文件。第一个参数是要删除的文件或文件夹(甚至是不存在的)。您可以在第二个参数的对象中使用 recursive
和 force
选项来模拟带有 rm
选项的 -rf
Shell 命令实用程序的行为。
"use strict";
require("fs").promises.rm("directory", {recursive: true, force: true}).then(() => {
console.log("removed");
}).catch(error => {
console.error(error.message);
});