'NodeJS recursively list files in directory

I am trying to list all files in a directory (and files within any subdirectories) with the following code:

var fs = require('fs')

var walk = function(directoryName) {
  fs.readdir(directoryName, function(e, files) {
    files.forEach(function(file) {
      fs.stat(file, function(e, f) {
        if (f.isDirectory()) {
          walk(file)
        } else {
          console.log('- ' + file)
        }
      })
    })
  })
}

walk(__dirname)

However, when my code attempts to invoke walk(file) on line 8 I get the following error:

TypeError: Cannot call method 'isDirectory' of undefined
    at program.js:7:15
    at Object.oncomplete (fs.js:107:15)

Why is f undefined? If I have the directory structure below, shouldn't the code identify aaa.txt and bbb.txt as files, my_dir as a directory at which point it recursively calls walk and begins the process again (with zzz.txt being the value of f)?

- aaa.txt
- bbb.txt
+ my_dir
    - zzz.txt


Solution 1:[1]

Function fs.readdir lists the simple file names in that directory, not their absolute path. This is why the program failed to find them, thus leading to an error in fs.stat.

Here's the solution: concatenate the directory path name to the file.

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

var walk = function(directoryName) {
  fs.readdir(directoryName, function(e, files) {
    if (e) {
      console.log('Error: ', e);
      return;
    }
    files.forEach(function(file) {
      var fullPath = path.join(directoryName,file);
      fs.stat(fullPath, function(e, f) {
        if (e) {
          console.log('Error: ', e);
          return;
        }
        if (f.isDirectory()) {
          walk(fullPath);
        } else {
          console.log('- ' + fullPath);
        }
      });
    });
  });
};

Solution 2:[2]

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

var walk = function(directoryName) {

  fs.readdir(directoryName, function(e, files) {
    files.forEach(function(file) {
      fs.stat(directoryName + path.sep + file, function(e, f) {

        if (f.isDirectory()) {
          walk(directoryName + path.sep + file)
        } else {
          console.log(' - ' + file)
        }
      })
    })
  })
}

walk(__dirname)

Solution 3:[3]

Here's a version for async/await:

const { promises: fs } = require("fs");
const path = require("path");

async function walk(dir) {
    const entries = await fs.readdir(dir);
    let ret = [];
    for (const entry of entries) {
        const fullpath = path.resolve(dir, entry);
        const info = await fs.stat(fullpath);
        if (info.isDirectory()) {
            ret = [...ret, ...(await walk(fullpath))];
        } else {
            ret = [...ret, fullpath];
        }
    }
    return ret;
}

(async function () {
    console.log(await walk("/path/to/some/dir"));
})();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 E_net4 - Krabbe mit Hüten
Solution 2 wayne
Solution 3 Kuba Orlik