Walking a directory with Node.js


Question

I've got a problem with this code in node.js. I want to recursively walk through a directory tree and apply the callback action to every file in the tree. This is my code at the moment:

var fs = require("fs");

// General function
var dive = function (dir, action) {
  // Assert that it's a function
  if (typeof action !== "function")
    action = function (error, file) { };

  // Read the directory
  fs.readdir(dir, function (err, list) {
    // Return the error if something went wrong
    if (err)
      return action(err);

    // For every file in the list
    list.forEach(function (file) {
      // Full path of that file
      path = dir + "/" + file;
      // Get the file's stats
      fs.stat(path, function (err, stat) {
        console.log(stat);
        // If the file is a directory
        if (stat && stat.isDirectory())
          // Dive into the directory
          dive(path, action);
        else
          // Call the action
          action(null, path);
      });
    });
  });
};

The problem is that in the for each loop stat is called for every file via the variable path. When the callback is called, path already has another value and so it dives into the wrong directories or calls the action for the wrong files.

Probably this problem could easily get solved by using fs.statSync, but this is not the solution I would prefer, since it is blocking the process.

1
18
4/9/2014 12:40:00 AM

Accepted Answer

var path = dir + "/" + file;

You forgot to make path a local variable. Now it won't be changed behind your back in the loop.

14
8/12/2011 2:58:30 PM

Use node-dir for this. Because you need a separate action for directories and files, I'll give you 2 simple iterators using node-dir.

Asynchronously iterate the files of a directory and its subdirectories and pass an array of file paths to a callback.

var dir = require('node-dir');

dir.files(__dirname, function(err, files) {
  if (err) throw err;
  console.log(files);
  //we have an array of files now, so now we'll iterate that array
  files.forEach(function(filepath) {
    actionOnFile(null, filepath);
  })
});

Asynchronously iterate the subdirectories of a directory and its subdirectories and pass an array of directory paths to a callback.

var dir = require('node-dir');

dir.subdirs(__dirname, function(err, subdirs) {
  if (err) throw err;
  console.log(subdirs);
  //we have an array of subdirs now, so now we'll iterate that array
  subdirs.forEach(function(filepath) {
    actionOnDir(null, filepath);
  })
});

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon