Il y a essentiellement deux façons d'y parvenir. Dans un environnement asynchrone, vous remarquerez qu'il existe deux types de boucles: série et parallèle. Une boucle série attend la fin d'une itération avant de passer à l'itération suivante - cela garantit que chaque itération de la boucle se termine dans l'ordre. Dans une boucle parallèle, toutes les itérations sont démarrées en même temps, et l'une peut se terminer avant une autre, cependant, c'est beaucoup plus rapide qu'une boucle série. Donc, dans ce cas, il est probablement préférable d'utiliser une boucle parallèle car peu importe l'ordre dans lequel la marche se termine, tant qu'elle se termine et renvoie les résultats (sauf si vous les souhaitez 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 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();
}
});
})();
});
};
Et pour le tester sur votre répertoire personnel (ATTENTION: la liste des résultats sera énorme si vous avez beaucoup de choses dans votre répertoire personnel):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
EDIT: exemples améliorés.
file = dir + '/' + file;
Ce n'est pas recommandé. Vous devez utiliser:var path = require('path'); file = path.resolve(dir, file);
path.resolve(...)
vous obtiendrez un chemin d'accès approprié que vous soyez sur Windows ou Unix :) Cela signifie que vous obtiendrez quelque chose commeC:\\some\\foo\\path
sur Windows et/some/foo/path
sur les systèmes Unixrequire('node-dir').files(__dirname, function(err, files) { console.log(files); });
!--
syntaxe, une question a été posée à ce sujetCelui-ci utilise le maximum de nouvelles fonctionnalités buzzwordy disponibles dans le nœud 8, y compris Promises, util / promisify, destructuring, async-wait, map + réduire et plus, ce qui fait que vos collègues se grattent la tête en essayant de comprendre ce qui se passe.
Noeud 8+
Pas de dépendances externes.
Usage
Noeud 10.10+
Mis à jour pour le noeud 10+ avec encore plus de whizbang:
Notez qu'à partir du noeud 11.15.0, vous pouvez utiliser
files.flat()
au lieu deArray.prototype.concat(...files)
pour aplatir le tableau de fichiers.Noeud 11+
Si vous voulez faire exploser complètement la tête de tout le monde, vous pouvez utiliser la version suivante à l'aide d' itérateurs asynchrones . En plus d'être vraiment cool, il permet également aux consommateurs de retirer les résultats un par un, ce qui le rend mieux adapté aux très gros répertoires.
L'utilisation a changé car le type de retour est désormais un itérateur asynchrone au lieu d'une promesse
Si quelqu'un est intéressé, j'ai écrit plus sur les itérateurs asynchrones ici: https://qwtel.com/posts/software/async-generators-in-the-wild/
la source
subdir
etsubdirs
est trompeuse, car il peut s'agir en fait de fichiers (je suggère quelque chose commeitemInDir
ouitem_in_dir
ou simplement à laitem
place.), Mais cette solution semble plus propre que celle acceptée et est beaucoup moins de code. Je ne trouve pas non plus cela beaucoup plus compliqué que le code dans la réponse acceptée. +1require(fs).promises
et simplement laisser tomberutil.promisify
complètement. Personnellement, je alias fs à fs.promises.readdir
AKA l'objet options commereaddir(dir, {withFileTypes: true})
ceci retournera tous les éléments avec leurs informations de type, donc nous n'aurons pas besoin d'appelerstat
du tout pour obtenir les informations quireaddir
nous donnent maintenant arrière. Cela nous évite d'avoir à effectuer des appels sys supplémentaires. Détails iciwithFileTypes
. Merci pour le conseil.return Array.prototype.concat(...files);
par,let result = Array.prototype.concat(...files); return result.map(file => file.split('\\').join('/'));
vous pouvez vous assurer que les répertoires renvoient un "/" et non un "\". Si cela ne vous dérange pas, vous pouvez également le fairereturn result.map(file => file.replace(/\\/g, '/'));
Au cas où quelqu'un le trouverait utile, j'ai également mis au point une version synchrone .
Conseil: pour utiliser moins de ressources lors du filtrage. Filtrer dans cette fonction elle-même. Par exemple, remplacez
results.push(file);
par le code ci-dessous. Ajustez au besoin:la source
lstat
place? Ou bien ajoutez une vérification de récursivité pour limiter le niveau de récursivité.A. Jetez un œil au module de fichiers . Il a une fonction appelée marche:
C'est peut-être pour vous! Et oui, c'est asynchrone. Cependant, je pense que vous devrez agréger le chemin complet vous-même, si vous en avez besoin.
B. Une alternative, et même une de mes préférées: utilisez l'Unix
find
pour ça. Pourquoi refaire 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 d'œil:Find a un joli mécanisme de mise en cache intégré qui rend les recherches suivantes très rapides, tant que seuls quelques dossiers ont changé.
la source
Un autre joli paquet npm est glob .
npm install glob
Il est très puissant et devrait couvrir tous vos besoins récurrents.
Éditer:
En fait, je n'étais pas parfaitement satisfait de glob, alors j'ai créé readdirp .
Je suis très convaincu que son API facilite la recherche récursive de fichiers et de répertoires et l'application de filtres spécifiques très facilement.
Lisez sa documentation pour avoir une meilleure idée de ce qu'il fait et installez via:
npm install readdirp
la source
Je recommande d'utiliser node-glob pour accomplir cette tâche.
la source
Si vous souhaitez utiliser un package npm, la clé est plutôt bonne.
EDIT (2018):
Toute personne lisant ces derniers temps: L'auteur a déprécié ce package en 2015:
la source
denodify
cela? Le rappel est déclenché plusieurs fois (récursivement). Ainsi, l'utilisationQ.denodify(wrench.readdirRecursive)
ne renvoie que le premier résultat.J'ai adoré la réponse de chjj ci-dessus et je n'aurais pas pu créer ma version de la boucle parallèle sans ce début.
J'ai également créé un Gist . Commentaires bienvenus. Je commence toujours dans le domaine NodeJS, c'est donc une façon dont j'espère en savoir plus.
la source
Avec récursivité
Appel
la source
/
mais en utilisant lepath
module de :path.join(searchPath, file)
. De cette façon, vous obtiendrez des chemins corrects indépendamment du système d'exploitation.Utilisez node-dir pour produire exactement la sortie que vous aimez
la source
J'ai codé cela récemment et j'ai pensé qu'il serait logique de partager cela ici. Le code utilise la bibliothèque async .
Vous pouvez l'utiliser comme ceci:
la source
Une bibliothèque appelée Filehound est une autre option. Il recherchera récursivement un répertoire donné (répertoire de travail par défaut). Il prend en charge divers filtres, rappels, promesses et recherches de synchronisation.
Par exemple, recherchez tous les fichiers dans le répertoire de travail actuel (à l'aide de rappels):
Ou promet et spécifie un répertoire spécifique:
Consultez la documentation pour d'autres cas d'utilisation et des exemples d'utilisation: https://github.com/nspragg/filehound
Avertissement: je suis l'auteur.
la source
En utilisant async / wait, cela devrait fonctionner:
Vous pouvez utiliser bluebird.Promisify ou ceci:
Voir mon autre réponse pour une approche de générateur qui peut donner des résultats encore plus rapidement.
la source
Async
Sync
Lecture asynchrone
Remarque: les deux versions suivront des liens symboliques (identiques à l'original
fs.readdir
)la source
Consultez la bibliothèque final-fs . Il fournit une
readdirRecursive
fonction:la source
Mise en œuvre de la promesse autonome
J'utilise la bibliothèque de promesses when.js dans cet exemple.
J'ai inclus un paramètre facultatif
includeDir
qui inclura les répertoires dans la liste des fichiers s'il est défini surtrue
.la source
klaw et klaw-sync valent la peine d'être considérés pour ce genre de choses. Ils faisaient partie de node-fs-extra .
la source
Voici encore une autre implémentation. Aucune des solutions ci-dessus n'a de limiteur, et donc si votre structure de répertoire est grande, elles vont toutes se déborder et éventuellement manquer de ressources.
L'utilisation d'une concurrence de 50 fonctionne plutôt bien et est presque aussi rapide que les implémentations plus simples pour les petites structures de répertoires.
la source
Le module recursive-readdir possède cette fonctionnalité.
la source
J'ai modifié la réponse basée sur la promesse de Trevor Senior pour travailler avec Bluebird
la source
Pour le plaisir, voici une version basée sur le flux qui fonctionne avec la bibliothèque de flux highland.js. Il a été co-écrit par Victor Vu.
la source
Utilisation de Promises ( Q ) pour résoudre ce problème dans un style fonctionnel:
Il renvoie une promesse d'un tableau, vous pouvez donc l'utiliser comme:
la source
Je dois ajouter la bibliothèque de ponceuse Promise à la liste.
la source
Utilisation de bluebird promise.coroutine:
la source
Parce que tout le monde devrait écrire le sien, j'en ai fait un.
walk (dir, cb, endCb) cb (fichier) endCb (err | null)
SALE
la source
consultez loaddir https://npmjs.org/package/loaddir
npm install loaddir
Vous pouvez également utiliser
fileName
au lieu debaseName
si vous avez besoin de l'extension.Un bonus supplémentaire est qu'il surveillera également les fichiers et rappellera le rappel. Il y a des tonnes d'options de configuration pour le rendre extrêmement flexible.
Je viens de refaire le
guard
bijou de rubis en utilisant loaddir dans un court laps de tempsla source
Voici ma réponse. J'espère que cela peut aider quelqu'un.
Mon objectif est de faire en sorte que la routine de recherche puisse s'arrêter n'importe où et, pour un fichier trouvé, indique la profondeur relative du chemin d'origine.
la source
Voici une méthode récursive pour obtenir tous les fichiers, y compris les sous-répertoires.
la source
Un autre simple et utile
la source
C'est ainsi que j'utilise la fonction nodejs fs.readdir pour rechercher récursivement un répertoire.
Supposons que vous ayez un chemin appelé '/ database' dans la racine de vos projets de nœuds. Une fois cette promesse résolue, elle devrait cracher un tableau de chaque fichier sous «/ base de données».
la source