In my Node application I need to remove a directory which has some files, but fs.rmdir
only works on empty directories. How can I do this?
问题:
回答1:
There is a module for this called rimraf
(https://npmjs.org/package/rimraf). It provides the same functionality as rm -Rf
Async usage:
var rimraf = require("rimraf");
rimraf("/some/directory", function () { console.log("done"); });
Sync usage:
rimraf.sync("/some/directory");
回答2:
To remove folder synchronously
var fs = require('fs');
var deleteFolderRecursive = function(path) {
if (fs.existsSync(path)) {
fs.readdirSync(path).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);
}
};
回答3:
Most of the people using fs
with Node.js would like functions close to the "Unix way" of dealing with files. I'm using fs-extra to bring all the cool stuff :
fs-extra contains methods that aren't included in the vanilla Node.js fs package. Such as mkdir -p, cp -r, and rm -rf.
Even better, fs-extra is a drop in replacement for native fs. All methods in fs are unmodified and attached to it. It means that you can replace fs by fs-extra :
// this can be replaced
var fs = require('fs')
// by this
var fs = require('fs-extra')
And then you can remove a folder this way:
fs.removeSync('/tmp/myFolder');
//or
fs.remove('/tmp/myFolder', callback);
回答4:
My modified answer from @oconnecp (https://stackoverflow.com/a/25069828/3027390)
Uses path.join for better cross-platform experience. So, don't forget to require it.
var path = require('path');
Also renamed function to 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:
Here is an async version of @SharpCoder's answer
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:
I wrote this function called remove folder. It will recursively remove all the files and folders in a location. The only package it requires is async.
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:
If you are using node 8+ want asyncronicity and don't want external dependencies, here is the async/await version:
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);
}
}
回答8:
I reached here while trying to get over with the gulp
and I'm writing for further reaches.
gulp-clean
deprecated forgulp-rimraf
gulp-rimraf
deprecated in favor ofdelete-files-folders
When you want to delete files and folders using del
, you should append /**
for recursive deletion.
gulp.task('clean', function () {
return del(['some/path/to/delete/**']);
});
回答9:
Just use rmdir module! it's easy and simple.
回答10:
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))
}
回答11:
A quick and dirty way (maybe for testing) could be to directly use the exec
or spawn
method to invoke OS call to remove the directory. Read more on NodeJs child_process.
let exec = require('child_process').exec
exec('rm -Rf /tmp/*.zip', callback)
Downsides are:
- You are depending on underlying OS i.e. the same method would run in unix/linux but probably not in windows.
- You cannot hijack the process on conditions or errors. You just give the task to underlying OS and wait for the exit code to be returned.
Benefits:
- These processes can run asynchronously.
- You can listen for the output/error of the command, hence command output is not lost. If operation is not completed, you can check the error code and retry.
回答12:
Async version of @SharpCoder answer using fs.promises:
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);
}
};
回答13:
I wish there was a way to do this without additional modules for something so minuscule and common, but this is the best I could come up with.
Update: Should now work on Windows (tested Windows 10), and should also work on Linux/Unix/BSD/Mac systems.
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);
});
}
回答14:
Another alternative is using the fs-promise
module that provides promisified versions of the fs-extra
modules
you could then write like this example:
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)
note: async/await requires a recent nodejs version (7.6+)
回答15:
const fs = require('fs')
const path = require('path')
let _dirloc = '<path_do_the_directory>'
if(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!')
}
}
回答16:
This is one approach using promisify and two help functions (to and toAll) to resolve the promise.
It does all actions asynchrounous.
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)
}
};