nœud.js fs.readdir récursive recherche dans l'annuaire

toutes les idées sur une recherche de répertoire async en utilisant fs.readdir? Je me rends compte que nous pourrions introduire la récursion et appeler la fonction read directory avec le prochain répertoire à lire, mais je suis un peu inquiet que ce ne soit pas async...

des idées? J'ai regardé nœud-pied qui est excellent, mais ne me donne pas seulement les fichiers dans un tableau, comme readdir. Bien que

recherche de sortie comme...

['file1.txt', 'file2.txt', 'dir/file3.txt']
197
demandé sur Hallgrim 2011-04-29 07:44:22

30 réponses

il y a essentiellement deux façons d'accomplir ceci. Dans un environnement asynchrone, vous remarquerez qu'il y a deux types de boucles: série et parallèle. Une boucle en série attend qu'une itération se termine avant de passer à la prochaine itération - ce qui garantit que chaque itération de la boucle se termine dans l'ordre. Dans une boucle parallèle, toutes les itérations sont lancées en même temps, et l'une peut se terminer avant l'autre, cependant, elle est beaucoup plus rapide qu'une boucle série. Donc, dans ce cas, il est il est probablement préférable d'utiliser une boucle parallèle, car peu importe l'ordre dans lequel la marche se déroule, tant qu'elle se termine et renvoie les résultats (à moins que vous ne les vouliez dans l'ordre).

une boucle parallèle ressemblerait à ceci:

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

une boucle série ressemblerait à ceci:

var fs = require('fs');
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 = 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();
        }
      });
    })();
  });
};

Et de le tester sur votre répertoire home (AVERTISSEMENT: la liste des résultats sera énorme si vous avez beaucoup de choses dans votre maison répertoire):

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

modifier: exemples améliorés.

332
répondu chjj 2015-05-30 11:24:20

A. regardez le file module . Il a une fonction appelée walk:

"151930920 de fichier".walk (start, callback)

navigue dans une arborescence de fichiers, appelant la fonction de rappel pour chaque répertoire, passant par (null, dirPath, dirs, les fichiers).

C'est peut-être pour vous! Et oui, il est asynchrone. Cependant, je pense que vous devriez agréger les chemin d'accès complet de vous-même, si vous avez besoin d'eux.

B. une alternative, et même l'un de mes favoris: Utilisez le unix find pour cela. Pourquoi recommencer quelque chose qui a déjà été programmé? Peut-être pas exactement ce dont vous avez besoin, mais ça vaut quand même le coup de vérifier:

var execFile = require('child_process').execFile;
execFile('find', [ 'somepath/' ], function(err, stdout, stderr) {
  var file_list = stdout.split('\n');
  /* now you've got a list with full path file names */
});

Find a un mécanisme de cache intégré qui rend les recherches ultérieures très rapides, aussi longtemps que peu de dossiers ont changé.

82
répondu Johann Philipp Strathausen 2014-06-12 22:20:57

juste au cas où quelqu'un le trouve utile, j'ai aussi mis en place une version synchrone .

var walk = function(dir) {
    var results = [];
    var list = fs.readdirSync(dir);
    list.forEach(function(file) {
        file = dir + '/' + file;
        var stat = fs.statSync(file);
        if (stat && stat.isDirectory()) { 
            /* Recurse into a subdirectory */
            results = results.concat(walk(file));
        } else { 
            /* Is a file */
            results.push(file);
        }
    });
    return results;
}

Conseil: utiliser moins de ressources lors du filtrage. Filtrer dans cette fonction elle-même. Par exemple: Remplacer results.push(file); par le code ci-dessous. Ajuster au besoin:

    file_type = file.split(".").pop();
    file_name = file.split(/(\|\/)/g).pop();
    if (file_type == "json") results.push(file);
70
répondu Victor Powell 2018-03-01 17:24:33

un autre joli paquet npm est glob .

npm install glob

il est très puissant et devrait couvrir tous vos besoins récurrents.

Edit:

en fait, je n'étais pas parfaitement heureux avec glob, donc j'ai créé readdirp .

je suis très confiant que son API rend la recherche de fichiers et de répertoires récursivement et l'application de filtres spécifiques très facile.

lire à travers sa documentation pour obtenir une meilleure idée de ce qu'il fait et installer via:

npm install readdirp

36
répondu Thorsten Lorenz 2012-08-13 01:45:09

je recommande d'utiliser node-glob pour accomplir cette tâche.

var glob = require( 'glob' );  

glob( 'dirname/**/*.js', function( err, files ) {
  console.log( files );
});
24
répondu Diogo Cardoso 2015-03-10 23:58:19

celui-ci utilise la quantité maximale de nouvelles fonctionnalités buzzwordy disponibles dans le noeud 8, y compris les promesses, util/promisify, la déstructuration, async-wait, map+reduce et plus encore, ce qui fait que vos collègues se grattent la tête alors qu'ils essaient de comprendre ce qui se passe.

pas de dépendances externes (noeud 8+).

const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);

async function getFiles(dir) {
  const subdirs = await readdir(dir);
  const files = await Promise.all(subdirs.map(async (subdir) => {
    const res = resolve(dir, subdir);
    return (await stat(res)).isDirectory() ? getFiles(res) : res;
  }));
  return files.reduce((a, f) => a.concat(f), []);
}

Utilisation:

getFiles(__dirname)
  .then(files => console.log(files))
  .catch(e => console.error(e));
22
répondu qwtel 2018-09-06 03:09:47

si vous voulez utiliser un paquet npm, clé est assez bon.

var wrench = require("wrench");

var files = wrench.readdirSyncRecursive("directory");

wrench.readdirRecursive("directory", function (error, files) {
    // live your dreams
});

EDIT (2018):

toute personne lisant ces derniers temps: l'auteur a déprécié ce paquet en 2015:

clé à molette.js est obsolète, et n'a pas été mis à jour depuis un certain temps. je recommande fortement d'utiliser fs-extra pour faire n'importe quel système de fichiers supplémentaire opérations.

15
répondu Domenic 2018-02-13 15:13:00

j'ai adoré la réponse à partir de chjj ci-dessus et n'aurait pas été en mesure de créer ma version de la boucle parallèle sans que commencer.

var fs = require("fs");

var tree = function(dir, done) {
  var results = {
        "path": dir
        ,"children": []
      };
  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) {
      fs.stat(dir + '/' + file, function(err, stat) {
        if (stat && stat.isDirectory()) {
          tree(dir + '/' + file, function(err, res) {
            results.children.push(res);
            if (!--pending){ done(null, results); }
          });
        } else {
          results.children.push({"path": dir + "/" + file});
          if (!--pending) { done(null, results); }
        }
      });
    });
  });
};

module.exports = tree;

j'ai créé l'Essentiel . Commentaires bienvenus. Je commence toujours dans le royaume de NodeJS donc c'est une façon que j'espère apprendre plus.

9
répondu kalisjoshua 2017-05-23 11:47:13

utiliser node-dir pour produire exactement la sortie que vous aimez

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 can iterate that array
  files.forEach(function(path) {
    action(null, path);
  })
});
8
répondu Christiaan Westerbeek 2014-05-14 14:46:34

Avec Récursion

var fs = require('fs')
var path = process.cwd()
var files = []

var getFiles = function(path, files){
    fs.readdirSync(path).forEach(function(file){
        var subpath = path + '/' + file;
        if(fs.lstatSync(subpath).isDirectory()){
            getFiles(subpath, files);
        } else {
            files.push(path + '/' + file);
        }
    });     
}

appel

getFiles(path, files)
console.log(files) // will log all files in directory
6
répondu Loourr 2016-04-19 22:54:05

j'ai codé ceci récemment, et j'ai pensé qu'il serait logique de partager ceci ici. Le code utilise la bibliothèque async .

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

var scan = function(dir, suffix, callback) {
  fs.readdir(dir, function(err, files) {
    var returnFiles = [];
    async.each(files, function(file, next) {
      var filePath = dir + '/' + file;
      fs.stat(filePath, function(err, stat) {
        if (err) {
          return next(err);
        }
        if (stat.isDirectory()) {
          scan(filePath, suffix, function(err, results) {
            if (err) {
              return next(err);
            }
            returnFiles = returnFiles.concat(results);
            next();
          })
        }
        else if (stat.isFile()) {
          if (file.indexOf(suffix, file.length - suffix.length) !== -1) {
            returnFiles.push(filePath);
          }
          next();
        }
      });
    }, function(err) {
      callback(err, returnFiles);
    });
  });
};

Vous pouvez l'utiliser comme ceci:

scan('/some/dir', '.ext', function(err, files) {
  // Do something with files that ends in '.ext'.
  console.log(files);
});
4
répondu recidive 2013-04-08 15:15:29

découvrez les final-fs de la bibliothèque. Il fournit une fonction readdirRecursive :

ffs.readdirRecursive(dirPath, true, 'my/initial/path')
    .then(function (files) {
        // in the `files` variable you've got all the files
    })
    .otherwise(function (err) {
        // something went wrong
    });
3
répondu Szymon Wygnański 2014-02-03 11:33:54

une bibliothèque appelée Filehound est une autre option. Il effectue une recherche récursive dans un répertoire donné (répertoire de travail par défaut). Il supporte divers filtres, callbacks, promesses et recherches de synchronisation.

par exemple, rechercher dans le répertoire de travail courant tous les fichiers (en utilisant des callbacks):

const Filehound = require('filehound');

Filehound.create()
.find((err, files) => {
    if (err) {
        return console.error(`error: ${err}`);
    }
    console.log(files); // array of files
});

ou promet et spécifie un répertoire spécifique:

const Filehound = require('filehound');

Filehound.create()
.paths("/tmp")
.find()
.each(console.log);

consulter les docs pour autres cas d'utilisation et exemples d'utilisation: https://github.com/nspragg/filehound

Avertissement: je suis l'auteur.

3
répondu nickool 2016-11-14 19:28:38

en utilisant async / wait, cela devrait fonctionner:

const FS = require('fs');
const readDir = promisify(FS.readdir);
const fileStat = promisify(FS.stat);

async function getFiles(dir) {
    let files = await readDir(dir);

    let result = files.map(file => {
        let path = Path.join(dir,file);
        return fileStat(path).then(stat => stat.isDirectory() ? getFiles(path) : path);
    });

    return flatten(await Promise.all(result));
}

function flatten(arr) {
    return Array.prototype.concat(...arr);
}

vous pouvez utiliser oiseau bleu.Promisify ou:

/**
 * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
 *
 * @param {Function} nodeFunction
 * @returns {Function}
 */
module.exports = function promisify(nodeFunction) {
    return function(...args) {
        return new Promise((resolve, reject) => {
            nodeFunction.call(this, ...args, (err, data) => {
                if(err) {
                    reject(err);
                } else {
                    resolve(data);
                }
            })
        });
    };
};
3
répondu mpen 2017-02-23 00:39:58

Autonome promesse de la mise en œuvre

j'utilise le quand.js la promesse de la bibliothèque dans cet exemple.

var fs = require('fs')
, path = require('path')
, when = require('when')
, nodefn = require('when/node/function');

function walk (directory, includeDir) {
    var results = [];
    return when.map(nodefn.call(fs.readdir, directory), function(file) {
        file = path.join(directory, file);
        return nodefn.call(fs.stat, file).then(function(stat) {
            if (stat.isFile()) { return results.push(file); }
            if (includeDir) { results.push(file + path.sep); }
            return walk(file, includeDir).then(function(filesInDir) {
                results = results.concat(filesInDir);
            });
        });
    }).then(function() {
        return results;
    });
};

walk(__dirname).then(function(files) {
    console.log(files);
}).otherwise(function(error) {
    console.error(error.stack || error);
});

j'ai inclus un paramètre optionnel includeDir qui inclura les répertoires dans la liste des fichiers s'ils sont définis à true .

2
répondu x9hb8wcy6quezjk 2013-12-20 15:43:22

klaw et klaw-sync sont à envisager pour ce genre de chose. Ces faisaient partie de node-fs-extra .

2
répondu dat 2017-01-23 15:40:53

Voici encore une autre la mise en œuvre. Aucune des solutions ci-dessus n'a de limiteurs, et donc si votre structure de répertoire est grande, ils vont tous se bousculer et finir par manquer de ressources.

var async = require('async');
var fs = require('fs');
var resolve = require('path').resolve;

var scan = function(path, concurrency, callback) {
    var list = [];

    var walker = async.queue(function(path, callback) {
        fs.stat(path, function(err, stats) {
            if (err) {
                return callback(err);
            } else {
                if (stats.isDirectory()) {
                    fs.readdir(path, function(err, files) {
                        if (err) {
                            callback(err);
                        } else {
                            for (var i = 0; i < files.length; i++) {
                                walker.push(resolve(path, files[i]));
                            }
                            callback();
                        }
                    });
                } else {
                    list.push(path);
                    callback();
                }
            }
        });
    }, concurrency);

    walker.push(path);

    walker.drain = function() {
        callback(list);
    }
};

utilisant une simultanéité de 50 fonctionne assez bien, et est presque aussi rapide que des implémentations plus simples pour des structures de petits répertoires.

1
répondu Monkey Boson 2014-08-06 16:07:04

le module recursive-readdir possède cette fonctionnalité.

1
répondu thSoft 2014-11-25 00:19:39

j'ai modifié Trevor Senior Promesse réponse de travailler avec Bluebird

var fs = require('fs'),
    path = require('path'),
    Promise = require('bluebird');

var readdirAsync = Promise.promisify(fs.readdir);
var statAsync = Promise.promisify(fs.stat);
function walkFiles (directory) {
    var results = [];
    return readdirAsync(directory).map(function(file) {
        file = path.join(directory, file);
        return statAsync(file).then(function(stat) {
            if (stat.isFile()) {
                return results.push(file);
            }
            return walkFiles(file).then(function(filesInDir) {
                results = results.concat(filesInDir);
            });
        });
    }).then(function() {
        return results;
    });
}

//use
walkDir(__dirname).then(function(files) {
    console.log(files);
}).catch(function(e) {
    console.error(e); {
});
1
répondu Phil Mander 2015-01-24 21:51:34

pour le plaisir, voici une version à base de flux qui fonctionne avec highland.js flux de la bibliothèque. Il a été co-écrit par Victor Vu.

###
  directory >---m------> dirFilesStream >---------o----> out
                |                                 |
                |                                 |
                +--------< returnPipe <-----------+

  legend: (m)erge  (o)bserve

 + directory         has the initial file
 + dirListStream     does a directory listing
 + out               prints out the full path of the file
 + returnPipe        runs stat and filters on directories

###

_ = require('highland')
fs = require('fs')
fsPath = require('path')

directory = _(['someDirectory'])
mergePoint = _()
dirFilesStream = mergePoint.merge().flatMap((parentPath) ->
  _.wrapCallback(fs.readdir)(parentPath).sequence().map (path) ->
    fsPath.join parentPath, path
)
out = dirFilesStream
# Create the return pipe
returnPipe = dirFilesStream.observe().flatFilter((path) ->
  _.wrapCallback(fs.stat)(path).map (v) ->
    v.isDirectory()
)
# Connect up the merge point now that we have all of our streams.
mergePoint.write directory
mergePoint.write returnPipe
mergePoint.end()
# Release backpressure.  This will print files as they are discovered
out.each H.log
# Another way would be to queue them all up and then print them all out at once.
# out.toArray((files)-> console.log(files))
1
répondu Michael Connor 2015-09-10 16:08:24

utilisant des promesses ( Q ) pour résoudre ce dans un style fonctionnel:

var fs = require('fs'),
    fsPath = require('path'),
    Q = require('q');

var walk = function (dir) {
  return Q.ninvoke(fs, 'readdir', dir).then(function (files) {

    return Q.all(files.map(function (file) {

      file = fsPath.join(dir, file);
      return Q.ninvoke(fs, 'lstat', file).then(function (stat) {

        if (stat.isDirectory()) {
          return walk(file);
        } else {
          return [file];
        }
      });
    }));
  }).then(function (files) {
    return files.reduce(function (pre, cur) {
      return pre.concat(cur);
    });
  });
};

Il retourne une promesse d'un tableau, de sorte que vous pouvez l'utiliser comme:

walk('/home/mypath').then(function (files) { console.log(files); });
1
répondu Gunar Gessner 2015-11-25 13:18:17

je dois ajouter la Promesse à base de sander de la bibliothèque à la liste.

 var sander = require('sander');
 sander.lsr(directory).then( filenames => { console.log(filenames) } );
1
répondu IvanSanchez 2016-01-14 12:58:26

avec Bluebird promise.coroutine:

let promise = require('bluebird'),
    PC = promise.coroutine,
    fs = promise.promisifyAll(require('fs'));
let getFiles = PC(function*(dir){
    let files = [];
    let contents = yield fs.readdirAsync(dir);
    for (let i = 0, l = contents.length; i < l; i ++) {
        //to remove dot(hidden) files on MAC
        if (/^\..*/.test(contents[i])) contents.splice(i, 1);
    }
    for (let i = 0, l = contents.length; i < l; i ++) {
        let content = path.resolve(dir, contents[i]);
        let contentStat = yield fs.statAsync(content);
        if (contentStat && contentStat.isDirectory()) {
            let subFiles = yield getFiles(content);
            files = files.concat(subFiles);
        } else {
            files.push(content);
        }
    }
    return files;
});
//how to use
//easy error handling in one place
getFiles(your_dir).then(console.log).catch(err => console.log(err));
1
répondu alexcres 2016-08-25 06:11:46

parce que chacun devrait écrire le sien, j'en ai fait un.

à pied(dir, cb, endCb) cb(fichier) endCb (err | null)

sale

module.exports = walk;

function walk(dir, cb, endCb) {
  var fs = require('fs');
  var path = require('path');

  fs.readdir(dir, function(err, files) {
    if (err) {
      return endCb(err);
    }

    var pending = files.length;
    if (pending === 0) {
      endCb(null);
    }
    files.forEach(function(file) {
      fs.stat(path.join(dir, file), function(err, stats) {
        if (err) {
          return endCb(err)
        }

        if (stats.isDirectory()) {
          walk(path.join(dir, file), cb, function() {
            pending--;
            if (pending === 0) {
              endCb(null);
            }
          });
        } else {
          cb(path.join(dir, file));
          pending--;
          if (pending === 0) {
            endCb(null);
          }
        }
      })
    });

  });
}
0
répondu vvo 2013-03-05 16:11:22

découvrez loaddir https://npmjs.org/package/loaddir

npm install loaddir

  loaddir = require('loaddir')

  allJavascripts = []
  loaddir({
    path: __dirname + '/public/javascripts',
    callback: function(){  allJavascripts.push(this.relativePath + this.baseName); }
  })

Vous pouvez utiliser fileName au lieu de baseName si vous avez besoin de l'extension.

un bonus ajouté est qu'il va regarder les fichiers ainsi et appeler le rappel à nouveau. Il y a des tonnes d'options de configuration pour le rendre extrêmement flexible.

je viens de refaire le guard gemme de rubis à l'aide de loaddir dans peu de temps

0
répondu Funkodebat 2013-10-03 20:53:47

C'est ma réponse. J'espère que ça peut aider quelqu'un.

mon objectif est de faire que la routine de recherche peut s'arrêter n'importe où, et pour un fichier trouvé, indique la profondeur relative par rapport au chemin original.

var _fs = require('fs');
var _path = require('path');
var _defer = process.nextTick;

// next() will pop the first element from an array and return it, together with
// the recursive depth and the container array of the element. i.e. If the first
// element is an array, it'll be dug into recursively. But if the first element is
// an empty array, it'll be simply popped and ignored.
// e.g. If the original array is [1,[2],3], next() will return [1,0,[[2],3]], and
// the array becomes [[2],3]. If the array is [[[],[1,2],3],4], next() will return
// [1,2,[2]], and the array becomes [[[2],3],4].
// There is an infinity loop `while(true) {...}`, because I optimized the code to
// make it a non-recursive version.
var next = function(c) {
    var a = c;
    var n = 0;
    while (true) {
        if (a.length == 0) return null;
        var x = a[0];
        if (x.constructor == Array) {
            if (x.length > 0) {
                a = x;
                ++n;
            } else {
                a.shift();
                a = c;
                n = 0;
            }
        } else {
            a.shift();
            return [x, n, a];
        }
    }
}

// cb is the callback function, it have four arguments:
//    1) an error object if any exception happens;
//    2) a path name, may be a directory or a file;
//    3) a flag, `true` means directory, and `false` means file;
//    4) a zero-based number indicates the depth relative to the original path.
// cb should return a state value to tell whether the searching routine should
// continue: `true` means it should continue; `false` means it should stop here;
// but for a directory, there is a third state `null`, means it should do not
// dig into the directory and continue searching the next file.
var ls = function(path, cb) {
    // use `_path.resolve()` to correctly handle '.' and '..'.
    var c = [ _path.resolve(path) ];
    var f = function() {
        var p = next(c);
        p && s(p);
    };
    var s = function(p) {
        _fs.stat(p[0], function(err, ss) {
            if (err) {
                // use `_defer()` to turn a recursive call into a non-recursive call.
                cb(err, p[0], null, p[1]) && _defer(f);
            } else if (ss.isDirectory()) {
                var y = cb(null, p[0], true, p[1]);
                if (y) r(p);
                else if (y == null) _defer(f);
            } else {
                cb(null, p[0], false, p[1]) && _defer(f);
            }
        });
    };
    var r = function(p) {
        _fs.readdir(p[0], function(err, files) {
            if (err) {
                cb(err, p[0], true, p[1]) && _defer(f);
            } else {
                // not use `Array.prototype.map()` because we can make each change on site.
                for (var i = 0; i < files.length; i++) {
                    files[i] = _path.join(p[0], files[i]);
                }
                p[2].unshift(files);
                _defer(f);
            }
        });
    }
    _defer(f);
};

var printfile = function(err, file, isdir, n) {
    if (err) {
        console.log('-->   ' + ('[' + n + '] ') + file + ': ' + err);
        return true;
    } else {
        console.log('... ' + ('[' + n + '] ') + (isdir ? 'D' : 'F') + ' ' + file);
        return true;
    }
};

var path = process.argv[2];
ls(path, printfile);
0
répondu manbaum 2014-09-15 00:38:34

un autre simple et utile

function walkDir(root) {
    const stat = fs.statSync(root);

    if (stat.isDirectory()) {
        const dirs = fs.readdirSync(root).filter(item => !item.startsWith('.'));
        let results = dirs.map(sub => walkDir(`${root}/${sub}`));
        return [].concat(...results);
    } else {
        return root;
    }
}
0
répondu clinyong 2017-02-24 14:58:40

je suis réticent à ajouter une autre réponse à la pile, mais j'ai aimé cette réponse (le seul qui a utilisé async/attente), mais j'ai pensé qu'il avait besoin d'un peu de rangement et de simplification:

async function getFileDescendents(dir) {
  const fs = require('fs-promise'), path = require('path');
  let files = await fs.readdir(dir);
  let result = files.map(file => {
    let p = path.join(dir,file);
    return fs.stat(p).then(stat => stat.isDirectory() ? getFileDescendents(p) : p);
  });
  return Array.prototype.concat(...(await Promise.all(result))); // flatten
}

il est utilisé comme ceci:

let files = await getFileDescendents('./my_directory');
0
répondu Joe 2017-05-23 11:54:46

C'est comme ça que j'utilise les nodejs fs.fonction readdir pour effectuer une recherche récursive dans un répertoire.

const fs = require('fs');
const mime = require('mime-types');
const readdirRecursivePromise = path => {
    return new Promise((resolve, reject) => {
        fs.readdir(path, (err, directoriesPaths) => {
            if (err) {
                reject(err);
            } else {
                if (directoriesPaths.indexOf('.DS_Store') != -1) {
                    directoriesPaths.splice(directoriesPaths.indexOf('.DS_Store'), 1);
                }
                directoriesPaths.forEach((e, i) => {
                    directoriesPaths[i] = statPromise(`${path}/${e}`);
                });
                Promise.all(directoriesPaths).then(out => {
                    resolve(out);
                }).catch(err => {
                    reject(err);
                });
            }
        });
    });
};
const statPromise = path => {
    return new Promise((resolve, reject) => {
        fs.stat(path, (err, stats) => {
            if (err) {
                reject(err);
            } else {
                if (stats.isDirectory()) {
                    readdirRecursivePromise(path).then(out => {
                        resolve(out);
                    }).catch(err => {
                        reject(err);
                    });
                } else if (stats.isFile()) {
                    resolve({
                        'path': path,
                        'type': mime.lookup(path)
                    });
                } else {
                    reject(`Error parsing path: ${path}`);
                }
            }
        });
    });
};
const flatten = (arr, result = []) => {
    for (let i = 0, length = arr.length; i < length; i++) {
        const value = arr[i];
        if (Array.isArray(value)) {
            flatten(value, result);
        } else {
            result.push(value);
        }
    }
    return result;
};

disons que vous avez un chemin appelé '/database' dans votre root de projets de noeuds. Une fois cette promesse résolue, elle devrait recracher un tableau de chaque fichier sous '/database'.

readdirRecursivePromise('database').then(out => {
    console.log(flatten(out));
}).catch(err => {
    console.log(err);
});
0
répondu Jason Clay 2017-09-05 01:20:01

encore une autre réponse, mais cette fois en utilisant dactylographié:

/**
 * Recursively walk a directory asynchronously and obtain all file names (with full path).
 *
 * @param dir Folder name you want to recursively process
 * @param done Callback function, returns all files with full path.
 * @param filter Optional filter to specify which files to include, 
 *   e.g. for json files: (f: string) => /.json$/.test(f)
 */
const walk = (
  dir: string,
  done: (err: Error | null, results ? : string[]) => void,
  filter ? : (f: string) => boolean
) => {
  let results: string[] = [];
  fs.readdir(dir, (err: Error, list: string[]) => {
    if (err) {
      return done(err);
    }
    let pending = list.length;
    if (!pending) {
      return done(null, results);
    }
    list.forEach((file: string) => {
      file = path.resolve(dir, file);
      fs.stat(file, (err2, stat) => {
        if (stat && stat.isDirectory()) {
          walk(file, (err3, res) => {
            if (res) {
              results = results.concat(res);
            }
            if (!--pending) {
              done(null, results);
            }
          }, filter);
        } else {
          if (typeof filter === 'undefined' || (filter && filter(file))) {
            results.push(file);
          }
          if (!--pending) {
            done(null, results);
          }
        }
      });
    });
  });
};
0
répondu Erik Vullings 2018-05-15 08:20:24