7

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 
2
  • 2
    Try testing for e, there might have been an error. Commented Nov 9, 2014 at 12:07
  • 1
    you need to add you directoryName to the recursive walk as well. Commented Nov 9, 2014 at 12:48

4 Answers 4

8

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); } }); }); }); }; 
Sign up to request clarification or add additional context in comments.

Comments

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

Comments

1

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")); })(); 

Comments

1

A fully synchronous version, for those situations where you cannot use async:

const walk = (dir, files = []) => { const dirFiles = fs.readdirSync(dir) for (const f of dirFiles) { const stat = fs.lstatSync(dir + path.sep + f) if (stat.isDirectory()) { walk(dir + path.sep + f, files) } else { files.push(dir + path.sep + f) } } return files } const allFiles = walk(someDir) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.