getting all filenames in a directory with node.js

I can't find where in the documentation I can get all filenames in a directory.

You can use the fs.readdir or fs.readdirSync methods.

The difference between the two methods, is that the first one is asynchronous, so you have to provide a callback function that will be executed when the read process ends.

The second is synchronous, it will returns the file name array, but it will stop any further execution of your code until the read process ends.

The answer above does not perform a recursive search into the directory though. Here's what I did for 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);
});

IMO the most convinient way to do such tasks is to use a glob tool. Here's a glob package for node.js. Install with

npm install glob

Then use wild card to match filenames (example taken from 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.
})

Get files in all subdirs

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'))

Here's a simple solution using only the native fs and path modules:

function walk(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()) {
            walk(filePath, callback);
        }
    });
}

Then you just do:

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

Here's an asynchronous recursive version.

    function ( path, callback){
     // the callback gets ( err, files) where files is an array of file names
     if( typeof callback !== 'function' ) return
     var
      result = []
      , files = [ path.replace( /\/\s*$/, '' ) ]
     function traverseFiles (){
      if( files.length ) {
       var name = files.shift()
       fs.stat(name, function( err, stats){
        if( err ){
         if( err.errno == 34 ) traverseFiles()
    // in case there's broken symbolic links or a bad path
    // skip file instead of sending error
         else callback(err)
        }
        else if ( stats.isDirectory() ) fs.readdir( name, function( err, files2 ){
         if( err ) callback(err)
         else {
          files = files2
           .map( function( file ){ return name + '/' + file } )
           .concat( files )
          traverseFiles()
         }
        })
        else{
         result.push(name)
         traverseFiles()
        }
       })
      }
      else callback( null, result )
     }
     traverseFiles()
    }

function getFilesRecursiveSync(dir, fileList, optionalFilterFunction) {
    if (!fileList) {
        grunt.log.error("Variable 'fileList' is undefined or NULL.");
        return;
    }
    var files = fs.readdirSync(dir);
    for (var i in files) {
        if (!files.hasOwnProperty(i)) continue;
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()) {
            getFilesRecursiveSync(name, fileList, optionalFilterFunction);
        } else {
            if (optionalFilterFunction && optionalFilterFunction(name) !== true)
                continue;
            fileList.push(name);
        }
    }
}

Just a heads up: if you're planning to perform operations on each file in a directory, try vinyl-fs (which is used by gulp, the streaming build system).