Is node.js rmdir recursive ? Will it work on non empty directories?

后端 未结 22 1355
清歌不尽
清歌不尽 2021-01-31 13:41

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

相关标签:
22条回答
  • 2021-01-31 13:52

    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

    0 讨论(0)
  • 2021-01-31 13:53

    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);                                                                                                                                                                                                                       
          });                                                                                                                                                                                                                                       
        });                                                                                                                                                                                                                                          } }
    
    0 讨论(0)
  • 2021-01-31 13:58

    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
    
    0 讨论(0)
  • 2021-01-31 13:58

    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

    0 讨论(0)
  • 2021-01-31 14:00

    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

    0 讨论(0)
  • 2021-01-31 14:01

    This worked for me

    fs.rmdirSync(folderpath, {recursive: true});
    
    0 讨论(0)
提交回复
热议问题