Get all directories within directory nodejs

node.jsDirectory

node.js Problem Overview


I was hoping this would be a simple thing, but I cannot find anything out there to do so.

I just want to get all folders/directories within a given folder/directory.

So for example:

<MyFolder>
|- SomeFolder
|- SomeOtherFolder
|- SomeFile.txt
|- SomeOtherFile.txt
|- x-directory

I would expect to get an array of:

["SomeFolder", "SomeOtherFolder", "x-directory"]

Or the above with the path if that was how it was served...

So does anything already exist to do the above?

node.js Solutions


Solution 1 - node.js

Promise

const { promises: { readdir } } = require('fs')

const getDirectories = async source =>
  (await readdir(source, { withFileTypes: true }))
    .filter(dirent => dirent.isDirectory())
    .map(dirent => dirent.name)

Callback

const { readdir } = require('fs')

const getDirectories = (source, callback) =>
  readdir(source, { withFileTypes: true }, (err, files) => {
    if (err) {
      callback(err)
    } else {
      callback(
        files
          .filter(dirent => dirent.isDirectory())
          .map(dirent => dirent.name)
      )
    }
  })

Syncronous return

const { readdirSync } = require('fs')

const getDirectories = source =>
  readdirSync(source, { withFileTypes: true })
    .filter(dirent => dirent.isDirectory())
    .map(dirent => dirent.name)

Solution 2 - node.js

List directories using a path.

function getDirectories(path) {
  return fs.readdirSync(path).filter(function (file) {
    return fs.statSync(path+'/'+file).isDirectory();
  });
}

Solution 3 - node.js

Recursive solution

I came here in search of a way to get all of the subdirectories, and all of their subdirectories, etc. Building on the accepted answer, I wrote this:

const fs = require('fs');
const path = require('path');

function flatten(lists) {
  return lists.reduce((a, b) => a.concat(b), []);
}

function getDirectories(srcpath) {
  return fs.readdirSync(srcpath)
    .map(file => path.join(srcpath, file))
    .filter(path => fs.statSync(path).isDirectory());
}

function getDirectoriesRecursive(srcpath) {
  return [srcpath, ...flatten(getDirectories(srcpath).map(getDirectoriesRecursive))];
}

Solution 4 - node.js

This should do it:

CoffeeScript (sync)

fs = require 'fs'

getDirs = (rootDir) ->
	files = fs.readdirSync(rootDir)
	dirs = []

	for file in files
		if file[0] != '.'
			filePath = "#{rootDir}/#{file}"
			stat = fs.statSync(filePath)

			if stat.isDirectory()
				dirs.push(file)

	return dirs

CoffeeScript (async)

fs = require 'fs'

getDirs = (rootDir, cb) ->
	fs.readdir rootDir, (err, files) ->
		dirs = []

		for file, index in files
			if file[0] != '.'
				filePath = "#{rootDir}/#{file}"
				fs.stat filePath, (err, stat) ->
					if stat.isDirectory()
						dirs.push(file)
					if files.length == (index + 1)
						cb(dirs)

JavaScript (async)

var fs = require('fs');
var getDirs = function(rootDir, cb) { 
	fs.readdir(rootDir, function(err, files) { 
		var dirs = []; 
		for (var index = 0; index < files.length; ++index) { 
			var file = files[index]; 
			if (file[0] !== '.') { 
				var filePath = rootDir + '/' + file; 
				fs.stat(filePath, function(err, stat) {
					if (stat.isDirectory()) { 
						dirs.push(this.file); 
					} 
					if (files.length === (this.index + 1)) { 
						return cb(dirs); 
					} 
				}.bind({index: index, file: file})); 
			}
		}
	});
}

Solution 5 - node.js

Alternatively, if you are able to use external libraries, you can use filehound. It supports callbacks, promises and sync calls.

Using promises:

const Filehound = require('filehound');

Filehound.create()
  .path("MyFolder")
  .directory() // only search for directories
  .find()
  .then((subdirectories) => {
    console.log(subdirectories);
  });
                        

Using callbacks:

const Filehound = require('filehound');

Filehound.create()
  .path("MyFolder")
  .directory()
  .find((err, subdirectories) => {
    if (err) return console.error(err);

    console.log(subdirectories);
  });

Sync call:

const Filehound = require('filehound');

const subdirectories = Filehound.create()
  .path("MyFolder")
  .directory()
  .findSync();

console.log(subdirectories);

For further information (and examples), check out the docs: https://github.com/nspragg/filehound

Disclaimer: I'm the author.

Solution 6 - node.js

With node.js version >= v10.13.0, fs.readdirSync will return an array of fs.Dirent objects if withFileTypes option is set to true.

So you can use,

const fs = require('fs')

const directories = source => fs.readdirSync(source, {
   withFileTypes: true
}).reduce((a, c) => {
   c.isDirectory() && a.push(c.name)
   return a
}, [])

Solution 7 - node.js

 var getDirectories = (rootdir , cb) => {
    fs.readdir(rootdir, (err, files) => {
        if(err) throw err ;
        var dirs = files.map(filename => path.join(rootdir,filename)).filter( pathname => fs.statSync(pathname).isDirectory());
        return cb(dirs);
    })
    
 }
 getDirectories( myDirectories => console.log(myDirectories));``

Solution 8 - node.js

Using fs-extra, which promises the async fs calls, and the new await async syntax:

const fs = require("fs-extra");

async function getDirectories(path){
    let filesAndDirectories = await fs.readdir(path);

    let directories = [];
    await Promise.all(
        filesAndDirectories.map(name =>{
            return fs.stat(path + name)
            .then(stat =>{
                if(stat.isDirectory()) directories.push(name)
            })
        })
    );
    return directories;
}

let directories = await getDirectories("/")

Solution 9 - node.js

This answer does not use blocking functions like readdirSync or statSync. It does not use external dependencies nor find itself in the depths of callback hell.

Instead we use modern JavaScript conveniences like Promises and and async-await syntaxes. And asynchronous results are processed in parallel; not sequentially -

const { readdir, stat } =
  require ("fs") .promises

const { join } =
  require ("path")

const dirs = async (path = ".") =>
  (await stat (path)) .isDirectory ()
    ? Promise
        .all
          ( (await readdir (path))
              .map (p => dirs (join (path, p)))
          )
        .then
          ( results =>
              [] .concat (path, ...results)
          )
    : []

I'll install an example package, and then test our function -

$ npm install ramda
$ node

Let's see it work -

> dirs (".") .then (console.log, console.error)

[ '.'
, 'node_modules'
, 'node_modules/ramda'
, 'node_modules/ramda/dist'
, 'node_modules/ramda/es'
, 'node_modules/ramda/es/internal'
, 'node_modules/ramda/src'
, 'node_modules/ramda/src/internal'
]

Using a generalised module, Parallel, we can simplify the definition of dirs -

const Parallel =
  require ("./Parallel")

const dirs = async (path = ".") =>
  (await stat (path)) .isDirectory ()
    ? Parallel (readdir (path))
        .flatMap (f => dirs (join (path, f)))
        .then (results => [ path, ...results ])
    : []

The Parallel module used above was a pattern that was extracted from a set of functions designed to solve a similar problem. For more explanation, see this related Q&A.

Solution 10 - node.js

And a async version of getDirectories, you need the async module for this:

var fs = require('fs');
var path = require('path');
var async = require('async'); // https://github.com/caolan/async

// Original function
function getDirsSync(srcpath) {
  return fs.readdirSync(srcpath).filter(function(file) {
    return fs.statSync(path.join(srcpath, file)).isDirectory();
  });
}

function getDirs(srcpath, cb) {
  fs.readdir(srcpath, function (err, files) {
    if(err) { 
      console.error(err);
      return cb([]);
    }
    var iterator = function (file, cb)  {
      fs.stat(path.join(srcpath, file), function (err, stats) {
        if(err) { 
          console.error(err);
          return cb(false);
        }
        cb(stats.isDirectory());
      })
    }
    async.filter(files, iterator, cb);
  });
}

Solution 11 - node.js

You can use graph-fs
const {Node} = require("graph-fs");
const directory = new Node("/path/to/directory");

const subDirectories = directory.children.filter(child => child.is.directory);

Solution 12 - node.js

Fully async version with ES6, only native packages, fs.promises and async/await, does file operations in parallel:

const fs = require('fs');
const path = require('path');

async function listDirectories(rootPath) {
    const fileNames = await fs.promises.readdir(rootPath);
    const filePaths = fileNames.map(fileName => path.join(rootPath, fileName));
    const filePathsAndIsDirectoryFlagsPromises = filePaths.map(async filePath => ({path: filePath, isDirectory: (await fs.promises.stat(filePath)).isDirectory()}))
    const filePathsAndIsDirectoryFlags = await Promise.all(filePathsAndIsDirectoryFlagsPromises);
    return filePathsAndIsDirectoryFlags.filter(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.isDirectory)
        .map(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.path);
}

Tested, it works nicely.

Solution 13 - node.js

CoffeeScript version of this answer, with proper error handling:

fs = require "fs"
{join} = require "path"
async = require "async"

get_subdirs = (root, callback)->
	fs.readdir root, (err, files)->
		return callback err if err
		subdirs = []
		async.each files,
			(file, callback)->
				fs.stat join(root, file), (err, stats)->
					return callback err if err
					subdirs.push file if stats.isDirectory()
					callback null
			(err)->
				return callback err if err
				callback null, subdirs

Depends on async

Alternatively, use a module for this! (There are modules for everything. [citation needed])

Solution 14 - node.js

If you need to use all async version. You can have something like this.

  1. Record the directory length, uses it as an indicator to tell if all async stat tasks are finished.

  2. If the async stat tasks are finished, all the file stat has been checked, so call the callback

This will only work as long as Node.js is single thread, because it assumes no two async tasks will increase the counter at the same time.

'use strict';

var fs = require("fs");
var path = require("path");
var basePath = "./";

function result_callback(results) {
    results.forEach((obj) => {
        console.log("isFile: " + obj.fileName);
        console.log("fileName: " + obj.isFile);
    });
};

fs.readdir(basePath, (err, files) => {
    var results = [];
    var total = files.length;
    var finished = 0;

    files.forEach((fileName) => {
        // console.log(fileName);
        var fullPath = path.join(basePath, fileName);

        fs.stat(fullPath, (err, stat) => {
            // this will work because Node.js is single thread
            // therefore, the counter will not increment at the same time by two callback
            finished++;

            if (stat.isFile()) {
                results.push({
                    fileName: fileName,
                    isFile: stat.isFile()
                });
            }

            if (finished == total) {
                result_callback(results);
            }
        });
    });
});

As you can see, this is a "depth first" approach, and this could result in callback hell, and it is not quite "functional" . People try to solve this problem with Promise, by wrapping the async task into an Promise object.

'use strict';

var fs = require("fs");
var path = require("path");
var basePath = "./";

function result_callback(results) {
    results.forEach((obj) => {
        console.log("isFile: " + obj.fileName);
        console.log("fileName: " + obj.isFile);
    });
};

fs.readdir(basePath, (err, files) => {
    var results = [];
    var total = files.length;
    var finished = 0;

    var promises = files.map((fileName) => {
        // console.log(fileName);
        var fullPath = path.join(basePath, fileName);

        return new Promise((resolve, reject) => {
            // try to replace fullPath wil "aaa", it will reject
            fs.stat(fullPath, (err, stat) => {
                if (err) {
                    reject(err);
                    return;
                }

                var obj = {
                    fileName: fileName,
                    isFile: stat.isFile()
                };

                resolve(obj);
            });
        });
    });

    Promise.all(promises).then((values) => {
        console.log("All the promise resolved");
        console.log(values);
        console.log("Filter out folder: ");
        values
            .filter((obj) => obj.isFile)
            .forEach((obj) => {
                console.log(obj.fileName);
            });
    }, (reason) => {
        console.log("Not all the promise resolved");
        console.log(reason);
    });
});

Solution 15 - node.js

use fs、path module can got the folder. this use Promise. If your will get the fill, your can change isDirectory() to isFile() Nodejs--fs--fs.Stats.At last, you can get the file'name file'extname and so on Nodejs---Path

var fs = require("fs"),
path = require("path");
//your <MyFolder> path
var p = "MyFolder"
fs.readdir(p, function (err, files) {
    if (err) {
        throw err;
    }
    //this can get all folder and file under  <MyFolder>
    files.map(function (file) {
        //return file or folder path, such as **MyFolder/SomeFile.txt**
        return path.join(p, file);
    }).filter(function (file) {
        //use sync judge method. The file will add next files array if the file is directory, or not. 
        return fs.statSync(file).isDirectory();
    }).forEach(function (files) {
        //The files is array, so each. files is the folder name. can handle the folder.
        console.log("%s", files);
    });
});

Solution 16 - node.js

Just in case anyone else ends up here from a web search, and has Grunt already in their dependency list, the answer to this becomes trivial. Here's my solution:

/**
 * Return all the subfolders of this path
 * @param {String} parentFolderPath - valid folder path
 * @param {String} glob ['/*'] - optional glob so you can do recursive if you want
 * @returns {String[]} subfolder paths
 */
getSubfolders = (parentFolderPath, glob = '/*') => {
	return grunt.file.expand({filter: 'isDirectory'}, parentFolderPath + glob);
}

Solution 17 - node.js

Another recursive approach

Thanks to Mayur for knowing me about withFileTypes. I written following code for getting files of particular folder recursively. It can be easily modified to get only directories.

const getFiles = (dir, base = '') => readdirSync(dir, {withFileTypes: true}).reduce((files, file) => {
    const filePath = path.join(dir, file.name)
    const relativePath = path.join(base, file.name)
    if(file.isDirectory()) {
        return files.concat(getFiles(filePath, relativePath))
    } else if(file.isFile()) {
        file.__fullPath = filePath
        file.__relateivePath = relativePath
        return files.concat(file)
    }
}, [])

Solution 18 - node.js

functional programming

const fs = require('fs')
const path = require('path')
const R = require('ramda')

const getDirectories = pathName => {
    const isDirectory = pathName => fs.lstatSync(pathName).isDirectory()
    const mapDirectories = pathName => R.map(name => path.join(pathName, name), fs.readdirSync(pathName))
    const filterDirectories = listPaths => R.filter(isDirectory, listPaths)

    return {
        paths:R.pipe(mapDirectories)(pathName),
        pathsFiltered: R.pipe(mapDirectories, filterDirectories)(pathName)
    }
}

Solution 19 - node.js

You could use dree, if using a module is affordable

const dree = require('dree');

const options = {
  depth: 1
};
const fileCallback = function() {};

const directories = [];
const dirCallback = function(dir) {
 directories.push(dir.name);
};

dree.scan('./dir', {});

console.log(directories);

The directories which are directed children of the specified path ("./dir") will be printed.

If you do not put the option depth: 1, you would even obtain all the directories in a recursively way, so not only the directed children of the specified path.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGrofitView Question on Stackoverflow
Solution 1 - node.jsNick McCurdyView Answer on Stackoverflow
Solution 2 - node.jsTitlacauanView Answer on Stackoverflow
Solution 3 - node.jsPatrick McElhaneyView Answer on Stackoverflow
Solution 4 - node.jsnicksweetView Answer on Stackoverflow
Solution 5 - node.jsnickoolView Answer on Stackoverflow
Solution 6 - node.jsMayurView Answer on Stackoverflow
Solution 7 - node.jsJonathan bonzaliView Answer on Stackoverflow
Solution 8 - node.js1mike12View Answer on Stackoverflow
Solution 9 - node.jsMulanView Answer on Stackoverflow
Solution 10 - node.jsJumpLinkView Answer on Stackoverflow
Solution 11 - node.jsYairoproView Answer on Stackoverflow
Solution 12 - node.jsDavid VeszelovszkiView Answer on Stackoverflow
Solution 13 - node.js1j01View Answer on Stackoverflow
Solution 14 - node.jscode4jView Answer on Stackoverflow
Solution 15 - node.jsHowardView Answer on Stackoverflow
Solution 16 - node.jsArtif3xView Answer on Stackoverflow
Solution 17 - node.jsSheikh Abdul WahidView Answer on Stackoverflow
Solution 18 - node.jsRoy AlcalaView Answer on Stackoverflow
Solution 19 - node.jsEuberDeveloperView Answer on Stackoverflow