1. ホーム
  2. node.js

[解決済み】Node.js fs.readdir 再帰的ディレクトリ検索

2022-04-15 22:26:21

質問

fs.readdirを使った非同期ディレクトリ検索について、何かアイデアはありませんか?再帰性を導入して、次に読むディレクトリでread directory関数を呼び出すことができることは理解していますが、非同期でないことが少し心配です...。

何かアイデアはありますか?私が見たのは ノードウォーク は素晴らしいのですが、readdirのように配列の中のファイルだけを与えてくれるわけではありません。しかし

のような出力を探しています。

['file1.txt', 'file2.txt', 'dir/file3.txt']

解決方法は?

これを実現するには、基本的に2つの方法があります。非同期環境では、シリアルとパラレルという2種類のループがあることに気がつくでしょう。直列ループは、ある反復処理が完了するのを待ってから次の反復処理に移る。これにより、ループの各反復処理が順番に完了することが保証される。並列ループでは、すべての反復処理が同時に開始され、ある反復処理が先に完了する可能性がありますが、直列ループよりもはるかに高速に処理されます。この場合、並列ループを使用した方がよいでしょう。なぜなら、ウォークがどのような順序で完了しても、完了し結果を返せばよいからです(順番に結果を返したい場合は別ですが)。

並列ループは次のようになります。

var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
  var results = [];
  fs.readdir(dir, function(err, list) {
    if (err) return done(err);
    var pending = list.length;
    if (!pending) return done(null, results);
    list.forEach(function(file) {
      file = path.resolve(dir, file);
      fs.stat(file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          walk(file, function(err, res) {
            results = results.concat(res);
            if (!--pending) done(null, results);
          });
        } else {
          results.push(file);
          if (!--pending) done(null, results);
        }
      });
    });
  });
};

直列ループは次のようになります。

var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
  var results = [];
  fs.readdir(dir, function(err, list) {
    if (err) return done(err);
    var i = 0;
    (function next() {
      var file = list[i++];
      if (!file) return done(null, results);
      file = path.resolve(dir, file);
      fs.stat(file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          walk(file, function(err, res) {
            results = results.concat(res);
            next();
          });
        } else {
          results.push(file);
          next();
        }
      });
    })();
  });
};

そして、あなたのホームディレクトリでテストするために(警告:あなたのホームディレクトリに多くのものがある場合、結果リストは巨大になります)。

walk(process.env.HOME, function(err, results) {
  if (err) throw err;
  console.log(results);
});

EDIT: 例を改善しました。