I am just two days into node.js. I am attempting to write my own module, which uses fs (filesystem) api. The code is as below:
var fs=require('fs');
var path=require('path');
// pkg file name constant
const PKG_FILE = 'pkg.json';
module.exports = function(srcDir, targetDir, callback) {
console.log('checking dir: ', srcDir, '...');
fs.readdir(srcDir, function(err, files) {
// early return, in case of error.
if (err) return callback(err);
// look for pkg.json file and if found, iterate through
// the list of components
var pkgFile = path.join(srcDir, PKG_FILE);
console.log(pkgFile);
var pkg = fs.readFile(pkgFile, function(err, data) {
if (err) return callback(err);
var obj = JSON.parse(data);
for (var attr in obj) {
console.log(attr, " : ", obj[attr]);
}
});
});
}
In the above code, I am trying to return to the caller, via the statement
if (err) return callback(err);
However, when an fs error occurs, I get a different error indicating that callback is undefined. Exact error is below:
rvnath#rv ~/projects/comviva/mbs/node/siteright $ node pkgtest.js riu3
checking dir: riu3 ...
/home/rvnath/projects/comviva/mbs/node/siteright/libs/pkgcreator.js:17
if (err) return callback(err);
^
TypeError: undefined is not a function
at /home/rvnath/projects/comviva/mbs/node/siteright/libs/pkgcreator.js:17:20
at FSReqWrap.oncomplete (fs.js:95:15)
Does this mean that I am not supposed to call "return callback(err) in nested closures?
Thanks to anyone for correcting me.
regards.
EDIT
I am using my module as below.
rvnath#rv ~/projects/comviva/mbs/node/siteright $ cat pkgtest.js
var packager = require('./libs/pkgcreator');
packager(process.argv[2], function(err, files) {
//if (err) {
//console.log("some error occurred", err);
//return;
//}
console.log("files listing...");
files.forEach(function(file) {
console.log(file);
});
});
In case of success, I get the result correctly.
checking dir: /home/rvnath/projects/comviva/mbs/ecp/ecp_6.0 ...
/home/rvnath/projects/comviva/mbs/ecp/ecp_6.0/pkg.json
reading module: smp3
reading module: pushp
reading module: bulkp
reading module: drp
reading module: mop
reading module: ecp_ws
reading module: ecp_admin
but for failure, it says callback undefined.
As expected, you are not passing a callback to the function which you are exporting -- it is indeed undefined. Simply add an anonymous function as third parameter to the function from your module, and the problem should be gone.
packager(process.argv[2], function(err, files) {
// your code
}, function(err) {
// The actual callback
console.log('Sadly, something went wrong: ' + err);
});
I need to write file to the following path:
fs.writeFile('/folder1/folder2/file.txt', 'content', function () {…});
But '/folder1/folder2' path may not exists. So I get the following error:
message=ENOENT, open /folder1/folder2/file.txt
How can I write content to that path?
As of Node v10, this is built into the fs.mkdir function, which we can use in combination with path.dirname:
var fs = require('fs');
var getDirName = require('path').dirname;
function writeFile(path, contents, cb) {
fs.mkdir(getDirName(path), { recursive: true}, function (err) {
if (err) return cb(err);
fs.writeFile(path, contents, cb);
});
}
For older versions, you can use mkdirp:
var mkdirp = require('mkdirp');
var fs = require('fs');
var getDirName = require('path').dirname;
function writeFile(path, contents, cb) {
mkdirp(getDirName(path), function (err) {
if (err) return cb(err);
fs.writeFile(path, contents, cb);
});
}
If the whole path already exists, mkdirp is a noop. Otherwise it creates all missing directories for you.
This module does what you want: https://npmjs.org/package/writefile . Got it when googling for "writefile mkdirp". This module returns a promise instead of taking a callback, so be sure to read some introduction to promises first. It might actually complicate things for you.
The function I gave works in any case.
I find that the easiest way to do this is to use the outputFile() method from the fs-extra module.
Almost the same as writeFile (i.e. it overwrites), except that if the parent directory does not exist, it's created. options are what you'd pass to fs.writeFile().
Example:
var fs = require('fs-extra');
var file = '/tmp/this/path/does/not/exist/file.txt'
fs.outputFile(file, 'hello!', function (err) {
console.log(err); // => null
fs.readFile(file, 'utf8', function (err, data) {
console.log(data); // => hello!
});
});
It also has promise support out of the box these days!.
Edit
NodeJS version 10.12.0 has added a native support for both mkdir and mkdirSync to create the parent director recursively with recursive: true option as the following:
fs.mkdirSync(targetDir, { recursive: true });
And if you prefer fs Promises API, you can write
fs.promises.mkdir(targetDir, { recursive: true });
Original Answer
Create the parent directories recursively if they do not exist! (Zero dependencies)
const fs = require('fs');
const path = require('path');
function mkDirByPathSync(targetDir, { isRelativeToScript = false } = {}) {
const sep = path.sep;
const initDir = path.isAbsolute(targetDir) ? sep : '';
const baseDir = isRelativeToScript ? __dirname : '.';
return targetDir.split(sep).reduce((parentDir, childDir) => {
const curDir = path.resolve(baseDir, parentDir, childDir);
try {
fs.mkdirSync(curDir);
} catch (err) {
if (err.code === 'EEXIST') { // curDir already exists!
return curDir;
}
// To avoid `EISDIR` error on Mac and `EACCES`-->`ENOENT` and `EPERM` on Windows.
if (err.code === 'ENOENT') { // Throw the original parentDir error on curDir `ENOENT` failure.
throw new Error(`EACCES: permission denied, mkdir '${parentDir}'`);
}
const caughtErr = ['EACCES', 'EPERM', 'EISDIR'].indexOf(err.code) > -1;
if (!caughtErr || caughtErr && curDir === path.resolve(targetDir)) {
throw err; // Throw if it's just the last created dir.
}
}
return curDir;
}, initDir);
}
Usage
// Default, make directories relative to current working directory.
mkDirByPathSync('path/to/dir');
// Make directories relative to the current script.
mkDirByPathSync('path/to/dir', {isRelativeToScript: true});
// Make directories with an absolute path.
mkDirByPathSync('/path/to/dir');
Demo
Try It!
Explanations
[UPDATE] This solution handles platform-specific errors like EISDIR for Mac and EPERM and EACCES for Windows.
This solution handles both relative and absolute paths.
In the case of relative paths, target directories will be created (resolved) in the current working directory. To Resolve them relative to the current script dir, pass {isRelativeToScript: true}.
Using path.sep and path.resolve(), not just / concatenation, to avoid cross-platform issues.
Using fs.mkdirSync and handling the error with try/catch if thrown to handle race conditions: another process may add the file between the calls to fs.existsSync() and fs.mkdirSync() and causes an exception.
The other way to achieve that could be checking if a file exists then creating it, I.e, if (!fs.existsSync(curDir) fs.mkdirSync(curDir);. But this is an anti-pattern that leaves the code vulnerable to race conditions.
Requires Node v6 and newer to support destructuring. (If you have problems implementing this solution with old Node versions, just leave me a comment)
Perhaps most simply, you can just use the fs-path npm module.
Your code would then look like:
var fsPath = require('fs-path');
fsPath.writeFile('/folder1/folder2/file.txt', 'content', function(err){
if(err) {
throw err;
} else {
console.log('wrote a file like DaVinci drew machines');
}
});
With node-fs-extra you can do it easily.
Install it
npm install --save fs-extra
Then use the outputFile method instead of writeFileSync
const fs = require('fs-extra');
fs.outputFile('tmp/test.txt', 'Hey there!', err => {
if(err) {
console.log(err);
} else {
console.log('The file was saved!');
}
})
You can use
fs.stat('/folder1/folder2', function(err, stats){ ... });
stats is a fs.Stats type of object, you may check stats.isDirectory(). Depending on the examination of err and stats you can do something, fs.mkdir( ... ) or throw an error.
Reference
Update: Fixed the commas in the code.
Here's my custom function to recursively create directories (with no external dependencies):
var fs = require('fs');
var path = require('path');
var myMkdirSync = function(dir){
if (fs.existsSync(dir)){
return
}
try{
fs.mkdirSync(dir)
}catch(err){
if(err.code == 'ENOENT'){
myMkdirSync(path.dirname(dir)) //create parent dir
myMkdirSync(dir) //create dir
}
}
}
myMkdirSync(path.dirname(filePath));
var file = fs.createWriteStream(filePath);
Here is my function which works in Node 10.12.0. Hope this will help.
const fs = require('fs');
function(dir,filename,content){
fs.promises.mkdir(dir, { recursive: true }).catch(error => { console.error('caught exception : ', error.message); });
fs.writeFile(dir+filename, content, function (err) {
if (err) throw err;
console.info('file saved!');
});
}
Here's part of Myrne Stol's answer broken out as a separate answer:
This module does what you want: https://npmjs.org/package/writefile .
Got it when googling for "writefile mkdirp". This module returns a
promise instead of taking a callback, so be sure to read some
introduction to promises first. It might actually complicate things
for you.
let name = "./new_folder/" + file_name + ".png";
await driver.takeScreenshot().then(
function(image, err) {
require('mkdirp')(require('path').dirname(name), (err) => {
require('fs').writeFile(name, image, 'base64', function(err) {
console.log(err);
});
});
}
);
In Windows you can use this code:
try {
fs.writeFileSync( './/..//..//filename.txt' , 'the text to write in the file', 'utf-8' );
}
catch(e){
console.log(" catch XXXXXXXXX ");
}
This code in windows create file in 2 folder above the current folder.
but I Can't create file in C:\ Directly
The documentation for fs.rmdir is very short and doesn't explain the behavior of rmdir when the directory is not empty.
Q: What happens if I try to use this API to delete a non empty directory ?
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.
Install it
npm install rimraf
Or install it and save to 'package.json'
(other save options can be found in the npm-install docs)
npm install --save rimraf
Then you can do the following:
rmdir = require('rimraf');
rmdir('some/directory/with/files', function(error){});
Or in Coffeescript:
rmdir = require 'rimraf'
rmdir 'some/directory/with/files', (error)->
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
[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.
You will want to handle all the responses; but the idea is simple enough.
Short answer: node.js fs.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.
The problem here is that the node.js documentation refers to POSIX:
The Node.js API Docs File System API started out as
simple wrappers around standard POSIX functions.
This almost changes the question into a duplicate of:
Is there a listing of the POSIX API / functions?
The description for fs.rmdir is terse, but sufficient.
Asynchronous 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.
Node.js v12.10.0 introduced recursive option into fs.rmdir.
As fs.mkdir supports the same option since v10.12.0, both making and removing directory can be executed recursively.
$ 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
This worked for me
fs.rmdirSync(folderpath, {recursive: true});
Edit 2021:
Now it seems to have been replaced in v14 with:
fs.rmSync('./output', {recursive: true, force: true});
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 rimraf and 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.rmdir is not recursive.
You could instead use a recursive fs.readdir module like readdirp in order to find all files and directories .
Then remove all files, followed by all directories.
For an even simpler solution have a look at rimraf.
As of node v16, recursive fs.rmdir is now deprecated. The replacement is fs.rm.
Usage with promises:
const fs = require("fs/promises")
(async () => {
await fs.rm("directory", { recursive: true })
})()
Traditional:
const fs = require("fs")
fs.rm("directory", { recursive: true }, (err) => {
// Callback
})
The force option is also relevant to mention here as it will prevent the method from throwing errors if the folder is missing, which is useful if this is for cleaning up temporary files.
nodejs documentation
Use child_process.execFile it is faster.
NodeJS docs:
child_process.execFile is similar to child_process.exec() except it*
does not execute a subshell but rather the specified file directly.
This works. Mimicking 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
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).
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.
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:
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;
}
Figured this was a good excuse to take a dive into the source ;)
From what I can tell, fs.rmdir is bound to the rmdir function from unistd.h. From the POSIX man page for rmdir:
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].
In addition to the correct "no" answers, the rimraf package provides recursive delete functionality. It mimics rm -rf. It's also officially packaged by Ubuntu.
I realize this isn't exactly answering the question at hand, but I think this might be useful to someone searching here in the future (it would have been to me!): I made a little snippet that allows one to recursively delete only empty directories. If a directory (or any of its descendant directories) has content inside it, it is left alone:
var fs = require("fs");
var path = require("path");
var rmdir = function(dir) {
var empty = true, list = fs.readdirSync(dir);
for(var i = list.length - 1; i >= 0; i--) {
var filename = path.join(dir, list[i]);
var stat = fs.statSync(filename);
if(filename.indexOf('.') > -1) {
//There are files in the directory - we can't empty it!
empty = false;
list.splice(i, 1);
}
}
//Cycle through the list of sub-directories, cleaning each as we go
for(var i = list.length - 1; i >= 0; i--) {
filename = path.join(dir, list[i]);
if (rmdir(filename)) {
list.splice(i, 1);
}
}
//Check if the directory was truly empty
if (!list.length && empty) {
console.log('delete!');
fs.rmdirSync(dir);
return true;
}
return false;
};
https://gist.github.com/azaslavsky/661020d437fa199e95ab
most of the examples I see out there are synchronous implementations of recursively deleting a folder structure in node.
I've also seen a few asynchronous ones that dont actually work well.
I wrote and use one thats completely asynchronous: https://gist.github.com/yoavniran/adbbe12ddf7978e070c0
Removing NON-EMPTY directories SYNCHRONOUSLY:-
Following is the file structure -
var fs = require('fs');
fs.unlink('./stuff/writeMe.txt',function(){
fs.rmdirSync('stuff');
})
I am firstly removing the writeMe.txt file from stuff folder using code fs.unlink('./stuff/writeMe.txt') which makes the stuff folder empty and finally removing it using code fs.rmdirSync('stuff')
This function will recursively delete a directory or file that you specify, synchronously:
var path = require('path');
function deleteRecursiveSync(itemPath) {
if (fs.statSync(itemPath).isDirectory()) {
_.each(fs.readdirSync(itemPath), function(childItemName) {
deleteRecursiveSync(path.join(itemPath, childItemName));
});
fs.rmdirSync(itemPath);
} else {
fs.unlinkSync(itemPath);
}
}
I have not tested this function's behavior if:
the item does not exist, or
the item cannot be deleted (such as due to a permissions issue).
Recursive remove directory for Node.js
It turned out that Node.js fs module does not have a method to remove the directory and its content recursively. Instead you should go through the directory structure and remove atomic items, i.e. individual files and empty directories. So I found a nice gist by Takuo Kihira at https://gist.github.com/2367067 made in JavaScript and decided to make a CoffeeScript version of it:
tried to make it fail safe as sync removal will cause error if file or dir are in use at that time.
var path = require('path');
var fs = require('fs')
var dumpDirs = function (dir, name, cb) {
fs.readdir(dir, function (err, files) {
var dirs = [],
filePath, i = 0, l = files.length;
for (var i = 0; i < l; i++) {
filePath = path.join(dir, files[i]);
var stats = fs.lstatSync(filePath);
if (stats.isDirectory()) {
if (files[i].indexOf(name) != -1) {
dirs.push({
startOn: new Date(stats.ctime),
instance: files[i],
name: name
})
}
}
}
cb(dirs);
});
}
var removeDir = function (dir, callback) {
fs.readdir(dir, function (err, files) {
c = files.length;
(function remfile(i, cb) {
if (i >= c)
return cb();
var p = path.join(dir, files[i])
fs.unlink(p, function (err) {
if (err) console.log(err);
remfile(i + 1, cb)
});
})(0, function () {
fs.rmdir(dir, function (err) {
callback()
});
});
//for (var i = 0; i < c; i++) {
// fs.unlinkSync(path.join(dir, files[i]));
//};
});
}
dumpDirs(maindir, function (dirs) {
if (dirs && dirs.length > 0) {
(function rem(i, cb) {
if (i >= dirs.length) {
return cb();
}
var folder = path.join(dump, dirs[i].instance);
removeDir(folder, function () {
rem(i + 1, cb);
});
})(0, function () {
callback();
})
}
else {
callback();
}
});
Here is the coffee script prototype function I created for fluentnode that deletes a folder recursively
String::folder_Delete_Recursive = ->
path = #.toString()
if path.exists()
for file in path.files()
curPath = path.path_Combine(file)
if curPath.is_Folder()
curPath.folder_Delete_Recursive()
else
curPath.file_Delete()
fs.rmdirSync(path);
return path.not_Exists()
here is the test:
it 'folder_Create and folder_Delete' , ->
tmpDir = "./".temp_Name_In_Folder()
expect(tmpDir.folder_Exists()).to.be.false
expect(tmpDir.folder_Create()).to.equal(tmpDir.realPath())
expect(tmpDir.folder_Exists()).to.be.true
expect(tmpDir.folder_Delete()).to.be.true
expect(tmpDir.folder_Exists()).to.be.false
it 'folder_Delete_Recursive' , ->
tmpDir = "./" .temp_Name_In_Folder().folder_Create()
tmpFile = tmpDir.temp_Name_In_Folder().file_Create()
expect(tmpDir.folder_Delete_Recursive()).to.be.true
A neat synchronous version of rmdirSync.
/**
* use with try ... catch ...
*
* If you have permission to remove all file/dir
* and no race condition and no IO exception...
* then this should work
*
* uncomment the line
* if(!fs.exists(p)) return
* if you care the inital value of dir,
*
*/
var fs = require('fs')
var path = require('path')
function rmdirSync(dir,file){
var p = file? path.join(dir,file):dir;
// if(!fs.exists(p)) return
if(fs.lstatSync(p).isDirectory()){
fs.readdirSync(p).forEach(rmdirSync.bind(null,p))
fs.rmdirSync(p)
}
else fs.unlinkSync(p)
}
And a parallel IO, asynchronous version of rmdir. (faster)
/**
* NOTE:
*
* If there are no error, callback will only be called once.
*
* If there are multiple errors, callback will be called
* exactly as many time as errors occur.
*
* Sometimes, this behavior maybe useful, but users
* should be aware of this and handle errors in callback.
*
*/
var fs = require('fs')
var path = require('path')
function rmfile(dir, file, callback){
var p = path.join(dir, file)
fs.lstat(p, function(err, stat){
if(err) callback.call(null,err)
else if(stat.isDirectory()) rmdir(p, callback)
else fs.unlink(p, callback)
})
}
function rmdir(dir, callback){
fs.readdir(dir, function(err,files){
if(err) callback.call(null,err)
else if( files.length ){
var i,j
for(i=j=files.length; i--; ){
rmfile(dir,files[i], function(err){
if(err) callback.call(null, err)
else if(--j === 0 ) fs.rmdir(dir,callback)
})
}
}
else fs.rmdir(dir, callback)
})
}
Anyway, if you want a sequential IO, and callback be called exactly once (either success or with first error encountered). Replace this rmdir with the above. (slower)
function rmdir(dir, callback){
fs.readdir(dir, function(err,files){
if(err) callback.call(null,err)
else if( files.length ) rmfile(dir, files[0], function(err){
if(err) callback.call(null,err)
else rmdir(dir, callback)
})
else fs.rmdir(dir, callback)
})
}
All of them depend ONLY on node.js and should be portable.
This post was getting the top answer from google but none of the answers gives a solution that:
doesn't make use of sync functions
doesn't require external libraries
doesn't use bash directly
Here is my async solution which doesn't assume anything else than node installed:
const fs = require('fs'); const path = require('path');
function rm(path){
return stat(path).then((_stat) => {
if(_stat.isDirectory()){
return ls(path)
.then((files) => Promise.all(files.map(file => rm(Path.join(path, file)))))
.then(() => removeEmptyFolder(path));
}else{
return removeFileOrLink(path);
} });
function removeEmptyFolder(path){
return new Promise((done, err) => {
fs.rmdir(path, function(error){
if(error){ return err(error); }
return done("ok");
});
}); }
function removeFileOrLink(path){
return new Promise((done, err) => {
fs.unlink(path, function(error){
if(error){ return err(error); }
return done("ok");
});
}); }
function ls(path){
return new Promise((done, err) => {
fs.readdir(path, function (error, files) {
if(error) return err(error)
return done(files)
});
}); }
function stat(path){
return new Promise((done, err) => {
fs.stat(path, function (error, _stat) {
if(error){ return err(error); }
return done(_stat);
});
}); } }
Following on #geedew's answer.
Here is an asynchronous implementation of rm -r (ie you can pass a path to a file or directory). I'm not an experienced nodejs developer and appreciate any suggestions or constructive criticism.
var fs = require('fs');
function ResultsCollector (numResultsExpected, runWhenDone) {
this.numResultsExpected = numResultsExpected,
this.runWhenDone = runWhenDone;
this.numResults = 0;
this.errors = [];
this.report = function (err) {
if (err) this.errors.push(err);
this.numResults++;
if (this.numResults == this.numResultsExpected) {
if (this.errors.length > 0) return runWhenDone(this.errors);
else return runWhenDone();
}
};
}
function rmRasync(path, cb) {
fs.lstat(path, function(err, stats) {
if (err && err.code == 'ENOENT') return cb(); // doesn't exist, nothing to do
else if (err) {
return cb(err);
}
if (stats.isDirectory()) {
fs.readdir(path, function (err, files) {
if (err) return cb(err);
var resultsCollector = new ResultsCollector(files.length, function (err) {
if (err) return cb(err);
fs.rmdir(path, function (err) {
if (err) return cb(err);
return cb();
});
});
files.forEach(function (file) {
var filePath = path + '/' + file;
return rmRasync(filePath, function (err) {
return resultsCollector.report(err);
});
});
});
}
else { // file.
// delete file or link
fs.unlink(path, function (err) {
if (err) return cb(err);
return cb();
});
}
});
};
Invoke like so:
rmRasync('/path/to/some/file/or/dir', function (err) {
if (err) return console.error('Could not rm', err);
// else success
});
Surprisingly verbose and bad answers here...
To delete a non-empty directory on most systems:
import * as cp from 'child_process';
const dir = '/the/dir/to/remove';
const k = cp.spawn('bash');
k.stdin.end(`rm -rf "${dir}"`);
k.once('exit', code => {
// check the exit code
// now you are done
});
this will work on MacOS and Linux, but it might not work on some Windows OS.