Answers:
为此有一个名为rimraf
(https://npmjs.org/package/rimraf)的模块。它提供的功能与rm -Rf
异步用法:
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
同步使用情况:
rimraf.sync("/some/directory");
deleteFolderRecursive
下面的答案中的功能?
recursive
选项:stackoverflow.com/a/57866165/6269864
同步删除文件夹
const fs = require('fs');
const Path = require('path');
const deleteFolderRecursive = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).forEach((file, index) => {
const curPath = Path.join(path, file);
if (fs.lstatSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
var curPath = path + "/" + file;
与var curPath = p.join(path, file);
提供包括你的路径模块:var p = require("path")
path.join(dirpath, file)
应该比path + "/" + file
fs
与Node.js一起使用的大多数人都希望函数类似于处理文件的“ Unix方式”。我正在使用fs-extra带来所有很酷的东西:
fs-extra包含香草Node.js fs软件包中未包含的方法。例如mkdir -p,cp -r和rm -rf。
更好的是,fs-extra取代了本地fs。fs中的所有方法均未修改且已附加。这意味着您可以将fs替换为fs-extra:
// 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);
removeSync('/tmp/myFolder')
从Node.js 12.10.0版本开始,它fs.rmdirSync
支持recursive
选项,因此您最终可以执行以下操作:
fs.rmdirSync(dir, { recursive: true });
该recursive
选项以递归方式删除整个目录。
recursive: true
并删除非空文件夹而不会引起投诉。
fs.rmdir(path[, options], callback)
或fs.rmdirSync(path[, options])
fs.rmdir
具有稳定性1。未来版本。不建议在生产环境中使用此功能。”
我从@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);
}
}
我通常不复活旧线程,但是这里有很多变动,并且没有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 });
await Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
return entry.isDirectory() ? rmdirs(fullPath) : unlink(fullPath);
}));
await rmdir(dir);
};
另一方面,对于路径遍历攻击的防护措施不适用于此功能,因为
rm -rf
,它接受一个参数,并允许用户进行rm -rf /
询问。脚本的责任是保护rm
程序本身。.isDirectory()
是false
对符号链接和取消关联不递归到。最后但并非最不重要的一点是,有一个罕见的竞争条件,即在此递归运行时,如果在正确的时间在此脚本外部取消链接或删除条目之一,则递归可能出错。由于这种情况在大多数环境中并不常见,因此很可能会被忽略。但是,如果需要(对于某些极端情况),可以使用以下稍微复杂一些的示例来缓解此问题:
exports.rmdirs = async function rmdirs(dir) {
let entries = await readdir(dir, { withFileTypes: true });
let results = await Promise.all(entries.map(entry => {
let fullPath = path.join(dir, entry.name);
let task = entry.isDirectory() ? rmdirs(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;
});
await rmdir(dir);
};
编辑:做isDirectory()
一个功能。最后删除实际目录。修复缺少的递归。
await
上你的Promise.all(…)
; 这是故意的吗?在当前状态下results.forEach
,代码似乎希望对结果进行迭代。我想念什么吗?
if (!fs.existsSync(dir)) return
readdir
将会引发错误。如果rmdir non-existing-dir
退出代码是错误的。尝试/捕捉是消费者的责任。使用fs函数时,这与Node docs中描述的方法相同。他们希望您尝试/捕捉并查看错误code
以确定执行该操作。额外的检查会引入比赛条件。
fs.exists
则没有竞争条件。PS这是一个很好的解决方案。
这是@SharpCoder的答案的异步版本
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);
});
});
});
};
我写了一个叫做删除文件夹的函数。它将递归地删除一个位置中的所有文件和文件夹。它唯一需要的包是异步的。
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)
})
})
})
}
如果您使用的节点8+需要异步并且不希望外部依赖,这是异步/等待版本:
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);
}
}
使用fs.promises的@SharpCoder答案的异步版本:
const fs = require('fs');
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);
}
};
我到达这里时正试图越过,gulp
我正在写进一步的书信。
gulp-clean
不推荐使用 gulp-rimraf
gulp-rimraf
不赞成使用 delete-files-folders
当您想使用删除文件和文件夹时del
,应追加/**
以进行递归删除。
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
实际上的软件包是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))
}
在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
超高速和防故障
您可以使用该lignator
软件包(https://www.npmjs.com/package/lignator),它比任何异步代码(例如rimraf)都要快,并且具有更高的防故障能力(尤其是在Windows中,文件删除不是即时的,并且文件可能被其他进程锁定)。
Windows上在15秒内删除了4,36 GB的数据,28042个文件,4 217个文件夹,而rimraf在旧硬盘上则是60秒。
const lignator = require('lignator');
lignator.remove('./build/');
同步文件夹随文件或仅文件一起删除。
我既不是献礼者,也不是贡献者,但是我找不到解决这个问题的好方法,因此我不得不找到办法...所以我希望您会喜欢:)
在许多情况下对我来说都很完美嵌套目录和子目录。递归函数时,请注意“ 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);
}
虽然recursive
是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);
});
});
});
}
2020更新
从版本12.10.0 开始,为选项添加了recursiveOption。
请注意,递归删除是实验性的。
因此,您可以进行同步:
fs.rmdirSync(dir, {recursive: true});
或异步:
fs.rmdir(dir, {recursive: true});
只需使用rmdir模块!这很简单。
另一种选择是使用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+)
一种快速而肮脏的方法(可能是用于测试)可能是直接使用exec
or spawn
方法来调用OS调用以删除目录。阅读更多关于NodeJs child_process的信息。
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
缺点是:
好处:
-f
标志以确保安全,或者在键入时确保他/她将不会删除所有内容。exec + rm
是我在测试期间经常使用的节点中有效且有用的命令。
我希望有一种方法可以在没有任何附加模块的情况下实现如此小巧和通用的功能,但这是我能想到的最好的方法。
更新:现在应该可以在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);
});
}
child_process.execFile
which不会调用外壳程序,而是显式传递参数。
这是一种使用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)
}
};
//不使用任何第三方库
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);
fs.unllinkSync(path.join(FOLDER_PATH, element);
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!')
}
}
fs.readdir(dirPath)
要对文件夹中的路径数组进行遍历,fs.unlink(filename)
以删除每个文件,然后最后fs.rmdir(dirPath)
删除当前为空的文件夹。如果需要递归,请检查fs.lstat(filename).isDirectory()
。