Coder Perfect

In Node.js, how do you get a list of all the names of all the files in a directory?

Problem

Using Node.js, I’m trying to retrieve a list of the names of all the files in a directory. I’d like an array of filenames as output. I’m not sure how I’m going to accomplish it.

Asked by resopollution

Solution #1

The fs.readdir and fs.readdirSync methods can be used. There’s no need to install anything because fs is built into the core of Node.js.

fs.readdir

const testFolder = './tests/';
const fs = require('fs');

fs.readdir(testFolder, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});

fs.readdirSync

const testFolder = './tests/';
const fs = require('fs');

fs.readdirSync(testFolder).forEach(file => {
  console.log(file);
});

The difference between the two methods is that the first is asynchronous, which means you must specify a callback function that will be executed after the read process is complete.

The second is synchronous; it will return the file name array but will halt any further code execution until the read procedure is completed.

Answered by Christian C. Salvadó

Solution #2

Using a glob tool is, in my opinion, the most convenient approach to accomplish such things. For node.js, here’s a glob package. Set up with

npm install glob

Then, to match filenames, utilize wild cards (sample obtained from the package’s website).

var glob = require("glob")

// options is optional
glob("**/*.js", options, function (er, files) {
  // files is an array of filenames.
  // If the `nonull` option is set, and nothing
  // was found, then files is ["**/*.js"]
  // er is an error object or null.
})

If you’re going to use globby, here’s an example of how to search for any xml files in the current folder.

var globby = require('globby');

const paths = await globby("**/*.xml");  

Answered by KFL

Solution #3

However, the answer above does not execute a recursive directory search. This is how I executed a recursive search (using node-walk: npm install walk)

var walk    = require('walk');
var files   = [];

// Walker options
var walker  = walk.walk('./test', { followLinks: false });

walker.on('file', function(root, stat, next) {
    // Add this file to the list of files
    files.push(root + '/' + stat.name);
    next();
});

walker.on('end', function() {
    console.log(files);
});

Answered by Ruben Tan

Solution #4

Obtain files from all subdirectories

const fs=require('fs');

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}

console.log(getFiles('path/to/dir'))

Answered by Tito100

Solution #5

Here’s a quick fix that only uses the native fs and path modules:

// sync version
function walkSync(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdirSync(currentDirPath).forEach(function (name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walkSync(filePath, callback);
        }
    });
}

or async version (which instead uses fs.readdir):

// async version with basic error handling
function walk(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdir(currentDirPath, function (err, files) {
        if (err) {
            throw new Error(err);
        }
        files.forEach(function (name) {
            var filePath = path.join(currentDirPath, name);
            var stat = fs.statSync(filePath);
            if (stat.isFile()) {
                callback(filePath, stat);
            } else if (stat.isDirectory()) {
                walk(filePath, callback);
            }
        });
    });
}

Then you just call (for sync version):

walkSync('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

or async version:

walk('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

The distinction is in the way nodes block while executing IO. Given that the API is identical, you may simply use the async version to get the best performance.

There is, however, one benefit to utilizing the synchronous version. It’s simpler to run some code right after the walk, like in the next statement after the walk. You’d need an extra means to know when you’re done with the async version. Perhaps start by drawing a map of all paths and then counting them. You might use the sync version for simple build/util scripts (vs high performance web servers) without causing any harm.

Answered by Ali

Post is based on https://stackoverflow.com/questions/2727167/how-do-you-get-a-list-of-the-names-of-all-files-present-in-a-directory-in-node-j