-
-
Save liangzan/807712 to your computer and use it in GitHub Desktop.
var fs = require('fs') | |
, path = require('path') | |
, _ = require('underscore'); | |
var rootPath = "/path/to/remove"; | |
removeDirForce(rootPath); | |
// path should have trailing slash | |
function removeDirForce(dirPath) { | |
fs.readdir(dirPath, function(err, files) { | |
if (err) { | |
console.log(JSON.stringify(err)); | |
} else { | |
if (files.length === 0) { | |
fs.rmdir(dirPath, function(err) { | |
if (err) { | |
console.log(JSON.stringify(err)); | |
} else { | |
var parentPath = path.normalize(dirPath + '/..') + '/'; | |
if (parentPath != path.normalize(rootPath)) { | |
removeDirForce(parentPath); | |
} | |
} | |
}); | |
} else { | |
_.each(files, function(file) { | |
var filePath = dirPath + file; | |
fs.stat(filePath, function(err, stats) { | |
if (err) { | |
console.log(JSON.stringify(err)); | |
} else { | |
if (stats.isFile()) { | |
fs.unlink(filePath, function(err) { | |
if (err) { | |
console.log(JSON.stringify(err)); | |
} | |
}); | |
} | |
if (stats.isDirectory()) { | |
removeDirForce(filePath + '/'); | |
} | |
} | |
}); | |
}); | |
} | |
} | |
}); | |
} |
Here's a synchronous version:
rmDir = function(dirPath) {
try { var files = fs.readdirSync(dirPath); }
catch(e) { return; }
if (files.length > 0)
for (var i = 0; i < files.length; i++) {
var filePath = dirPath + '/' + files[i];
if (fs.statSync(filePath).isFile())
fs.unlinkSync(filePath);
else
rmDir(filePath);
}
fs.rmdirSync(dirPath);
};
@guybedford nice!
@guybedford, ty :)
Maybe it will be usefull for someone. Extend @guybedfrod function, to remove all in dir but not dir itself.
rmDir = function(dirPath, removeSelf) {
if (removeSelf === undefined)
removeSelf = true;
try { var files = fs.readdirSync(dirPath); }
catch(e) { return; }
if (files.length > 0)
for (var i = 0; i < files.length; i++) {
var filePath = dirPath + '/' + files[i];
if (fs.statSync(filePath).isFile())
fs.unlinkSync(filePath);
else
rmDir(filePath);
}
if (removeSelf)
fs.rmdirSync(dirPath);
};
Call rmDir('path/to/dir')
to remove all inside dir and dir itself. Call rmDir('path/to/dir', false)
to remove all inside, but not dir itself.
you could replace:
var filePath = dirPath + '/' + files[i];
with:
var filePath = path.join(dirPath, files[i]);
and then it might even work on Windows...
That crawler and destroyer that @guybedford posted works great, just be careful to not have any npm link
s or symlinks for that matter :) Found that out the hard way.
@guybedford : Time saving 'code block',thank you.
Thanks! Need change rootPath to dirPath here L20
@liangzan Nice. 👍
@guybedford Bless your soul
I made an async/await version of @guybedford's code with some changes based on @iserdmi's, @willemx's, and @PWKad's comments.
It can accept object as a second argument that can allow delete just folder's content with { removeContentOnly: true }
or allow drilling symbolic links down with { drillDownSymlinks: true }
(by default it just deletes a symlink, not its content)
Usage: await rmdir('some/path')
or await rmdir('some/path', { (optionsDescridedAbove) })
let rmdir = async (dirPath, options = {}) => {
const
{ removeContentOnly = false, drillDownSymlinks = false } = options,
{ promisify } = require('util'),
path = require('path'),
fs = require('fs'),
readdirAsync = promisify(fs.readdir),
unlinkAsync = promisify(fs.unlink),
rmdirAsync = promisify(fs.rmdir),
lstatAsync = promisify(fs.lstat) // fs.lstat can detect symlinks, fs.stat can't
let
files
try {
files = await readdirAsync(dirPath)
} catch (e) {
throw new Error(e)
}
if (files.length) {
for (let fileName of files) {
let
filePath = path.join(dirPath, fileName),
fileStat = await lstatAsync(filePath),
isSymlink = fileStat.isSymbolicLink(),
isDir = fileStat.isDirectory()
if (isDir || (isSymlink && drillDownSymlinks)) {
await rmdir(filePath)
} else {
await unlinkAsync(filePath)
}
}
}
if (!removeContentOnly)
await rmdirAsync(dirPath)
}
Here's a synchronous version:
rmDir = function(dirPath) { try { var files = fs.readdirSync(dirPath); } catch(e) { return; } if (files.length > 0) for (var i = 0; i < files.length; i++) { var filePath = dirPath + '/' + files[i]; if (fs.statSync(filePath).isFile()) fs.unlinkSync(filePath); else rmDir(filePath); } fs.rmdirSync(dirPath); };
This worked for me.
A bit more structured :)
const {
readdirSync,
rmdirSync,
unlinkSync,
} = require('fs');
const { join } = require('path');
const isDir = path => {
try {
return statSync(path).isDirectory();
} catch (error) {
return false;
}
};
const getFiles = (path) =>
readdirSync(path)
.map(name => join(path, name));
const getDirectories = path =>
readdirSync(path)
.map(name => join(path, name))
.filter(isDir);
const rmDir = path => {
getDirectories(path).map(dir => rmDir(dir));
getFiles(path).map(file => unlinkSync(file));
rmdirSync(path);
};
@iserdmi Thanks. I needed a version that wouldn't delete the directory itself.
Maybe it will be usefull for someone. Extend @guybedfrod function, to remove all in dir but not dir itself.
rmDir = function(dirPath, removeSelf) { if (removeSelf === undefined) removeSelf = true; try { var files = fs.readdirSync(dirPath); } catch(e) { return; } if (files.length > 0) for (var i = 0; i < files.length; i++) { var filePath = dirPath + '/' + files[i]; if (fs.statSync(filePath).isFile()) fs.unlinkSync(filePath); else rmDir(filePath); } if (removeSelf) fs.rmdirSync(dirPath); };
Call
rmDir('path/to/dir')
to remove all inside dir and dir itself. CallrmDir('path/to/dir', false)
to remove all inside, but not dir itself.
This is helpful. Thanks!
I am not able to get this to work. It will fail based on the fact that if something is a directory, the function will call itself, remove that directory and then stop running. Not to mention the fact that the stats.isDirectory is returning true for files.