Grundsätzlich gibt es zwei Möglichkeiten, dies zu erreichen. In einer asynchronen Umgebung werden Sie feststellen, dass es zwei Arten von Schleifen gibt: serielle und parallele. Eine serielle Schleife wartet, bis eine Iteration abgeschlossen ist, bevor sie zur nächsten Iteration übergeht. Dies garantiert, dass jede Iteration der Schleife der Reihe nach abgeschlossen wird. In einer parallelen Schleife werden alle Iterationen gleichzeitig gestartet, und eine kann vor der anderen abgeschlossen werden. Sie ist jedoch viel schneller als eine serielle Schleife. In diesem Fall ist es wahrscheinlich besser, eine parallele Schleife zu verwenden, da es keine Rolle spielt, in welcher Reihenfolge der Spaziergang abgeschlossen wird, solange die Ergebnisse abgeschlossen sind und zurückgegeben werden (es sei denn, Sie möchten, dass sie in der richtigen Reihenfolge vorliegen).
Eine parallele Schleife würde folgendermaßen aussehen:
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);
}
});
});
});
};
Eine serielle Schleife würde folgendermaßen aussehen:
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();
}
});
})();
});
};
Und um es in Ihrem Home-Verzeichnis zu testen (WARNUNG: Die Ergebnisliste ist riesig, wenn Sie viele Dinge in Ihrem Home-Verzeichnis haben):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
EDIT: Verbesserte Beispiele.
file = dir + '/' + file;
Dies wird nicht empfohlen. Sie sollten verwenden:var path = require('path'); file = path.resolve(dir, file);
path.resolve(...)
Sie einen richtigen Pfad, egal ob Sie unter Windows oder Unix arbeiten :) Das bedeutet, dass Sie so etwas wieC:\\some\\foo\\path
unter Windows und/some/foo/path
auf Unix-Systemen erhaltenrequire('node-dir').files(__dirname, function(err, files) { console.log(files); });
!--
Syntax verwirrt sind , wurde eine Frage gestelltIn diesem Fall wird die maximale Anzahl neuer, in Knoten 8 verfügbarer, witziger Funktionen verwendet, einschließlich Versprechen, Nutzen / Versprechen, Destrukturieren, asynchrones Warten, Zuordnen + Reduzieren und mehr, sodass Ihre Mitarbeiter sich am Kopf kratzen, wenn sie herausfinden möchten, was passiert es geht voran.
Knoten 8+
Keine externen Abhängigkeiten.
Verwendung
Knoten 10.10+
Aktualisiert für Knoten 10+ mit noch mehr Whizbang:
Beachten Sie, dass Sie ab Knoten 11.15.0
files.flat()
anstelle von verwenden könnenArray.prototype.concat(...files)
zu .Knoten 11+
Wenn Sie alle völlig in die Luft jagen möchten, können Sie die folgende Version mit asynchronen Iteratoren verwenden . Es ist nicht nur wirklich cool, sondern ermöglicht es den Verbrauchern auch, die Ergebnisse einzeln abzurufen, wodurch es sich besser für wirklich große Verzeichnisse eignet.
Die Verwendung hat sich geändert, da der Rückgabetyp jetzt ein asynchroner Iterator anstelle eines Versprechens ist
Falls jemand interessiert ist, habe ich hier mehr über asynchrone Iteratoren geschrieben: https://qwtel.com/posts/software/async-generators-in-the-wild/
quelle
subdir
undsubdirs
ist irreführend, da es sich tatsächlich um Dateien handelt (ich schlage etwas wieitemInDir
oderitem_in_dir
oder sogar einfachitem
stattdessen vor), aber diese Lösung fühlt sich sauberer an als die akzeptierte und ist viel weniger Code. Ich finde es auch nicht viel komplizierter als den Code in der akzeptierten Antwort. +1require(fs).promises
und einfach ganz fallen lassenutil.promisify
. Persönlich alias ich fs zu fs.promises.readdir
AKA, das Optionsobjekt, soreaddir(dir, {withFileTypes: true})
dass alle Elemente mit ihren Typinformationen zurückgegeben werden. Wir müssen also überhaupt nicht aufrufenstat
, um die Informationen zu erhalten,readdir
die uns jetzt zur Verfügung stehen zurück. Dies erspart uns zusätzliche Systemanrufe. Details hierwithFileTypes
. Danke für den Tipp.return Array.prototype.concat(...files);
mitlet result = Array.prototype.concat(...files); return result.map(file => file.split('\\').join('/'));
Ihnen sicher , dass die Verz machen zurückkehren ein „/“ und kein „\“. Wenn Ihnen Regex nichts ausmacht, können Sie dies auch tunreturn result.map(file => file.replace(/\\/g, '/'));
Für den Fall, dass es jemand nützlich findet, habe ich auch eine synchrone Version zusammengestellt.
Tipp: Um beim Filtern weniger Ressourcen zu verbrauchen. Filtern Sie innerhalb dieser Funktion. ZB
results.push(file);
durch folgenden Code ersetzen . Nach Bedarf anpassen:quelle
lstat
stattdessen verwenden? Oder fügen Sie eine Rekursivitätsprüfung hinzu, um die Rekursivitätsstufe zu begrenzen.A. Sehen Sie sich das Dateimodul an . Es hat eine Funktion namens walk:
Das kann für Sie sein! Und ja, es ist asynchron. Ich denke jedoch, dass Sie die vollständigen Pfade selbst aggregieren müssten, wenn Sie sie benötigen würden.
B. Eine Alternative und sogar einer meiner Favoriten: Verwenden Sie dazu das Unix
find
. Warum nochmal etwas machen, das schon programmiert wurde? Vielleicht nicht genau das, was Sie brauchen, aber dennoch einen Besuch wert:Find verfügt über einen netten integrierten Caching-Mechanismus, der nachfolgende Suchvorgänge sehr schnell macht, solange sich nur wenige Ordner geändert haben.
quelle
Ein weiteres schönes npm-Paket ist glob .
npm install glob
Es ist sehr leistungsfähig und sollte alle Ihre wiederkehrenden Anforderungen abdecken.
Bearbeiten:
Ich war eigentlich nicht ganz zufrieden mit glob, also habe ich readdirp erstellt .
Ich bin sehr zuversichtlich, dass die API das rekursive Auffinden von Dateien und Verzeichnissen und das Anwenden bestimmter Filter sehr einfach macht.
Lesen Sie die Dokumentation durch , um eine bessere Vorstellung davon zu erhalten, was es tut, und installieren Sie es über:
npm install readdirp
quelle
Ich empfehle die Verwendung von Node-Glob , um diese Aufgabe zu erfüllen.
quelle
Wenn Sie ein npm-Paket verwenden möchten, ist der Schraubenschlüssel ziemlich gut.
EDIT (2018):
Jeder, der in letzter Zeit durchgelesen hat: Der Autor hat dieses Paket im Jahr 2015 abgelehnt:
quelle
denodify
das? Der Rückruf wird mehrmals (rekursiv) ausgelöst. Wenn Sie also verwenden, wirdQ.denodify(wrench.readdirRecursive)
nur das erste Ergebnis zurückgegeben.Ich mochte die Antwort von chjj oben und hätte ohne diesen Start meine Version der Parallelschleife nicht erstellen können.
Ich habe auch einen Kern erstellt . Kommentare willkommen. Ich fange immer noch im NodeJS-Bereich an, also hoffe ich, dass ich auf diese Weise mehr erfahren kann.
quelle
Verwenden Sie Node-Dir , um genau die Ausgabe zu erzeugen, die Sie mögen
quelle
Mit Rekursion
Berufung
quelle
/
mit dempath
Modul zu verbinden, sondern es zu verwenden :path.join(searchPath, file)
. Auf diese Weise erhalten Sie unabhängig vom Betriebssystem die richtigen Pfade.Ich habe dies kürzlich codiert und dachte, es wäre sinnvoll, dies hier zu teilen. Der Code verwendet die asynchrone Bibliothek .
Sie können es so verwenden:
quelle
Eine Bibliothek namens Filehound ist eine weitere Option. Es wird rekursiv ein bestimmtes Verzeichnis durchsucht (standardmäßig Arbeitsverzeichnis). Es unterstützt verschiedene Filter, Rückrufe, Versprechen und Synchronisierungssuchen.
Durchsuchen Sie beispielsweise das aktuelle Arbeitsverzeichnis nach allen Dateien (mithilfe von Rückrufen):
Oder verspricht und spezifiziert ein bestimmtes Verzeichnis:
Weitere Anwendungsfälle und Anwendungsbeispiele finden Sie in den Dokumenten: https://github.com/nspragg/filehound
Haftungsausschluss: Ich bin der Autor.
quelle
Mit async / await sollte dies funktionieren:
Sie können bluebird.Promisify oder dies verwenden:
In meiner anderen Antwort finden Sie einen Generatoransatz, mit dem Sie noch schneller Ergebnisse erzielen können.
quelle
Async
Synchronisieren
Async lesbar
Hinweis: Beide Versionen folgen Symlinks (wie das Original
fs.readdir
).quelle
Schauen Sie sich die final-fs- Bibliothek an. Es bietet eine
readdirRecursive
Funktion:quelle
Implementierung eines eigenständigen Versprechens
In diesem Beispiel verwende ich die Versprechungsbibliothek when.js.
Ich habe einen optionalen Parameter eingefügt,
includeDir
der Verzeichnisse in die Dateiliste aufnimmt, wenn er auf gesetzt isttrue
.quelle
klaw und klaw-sync sind eine Überlegung wert. Diese waren Teil von Node-Fs-Extra .
quelle
Hier ist noch eine weitere Implementierung. Keine der oben genannten Lösungen hat irgendwelche Begrenzer. Wenn Ihre Verzeichnisstruktur also groß ist, werden sie alle kaputt gehen und schließlich keine Ressourcen mehr haben.
Die Verwendung einer Parallelität von 50 funktioniert ziemlich gut und ist fast so schnell wie einfachere Implementierungen für kleine Verzeichnisstrukturen.
quelle
Das rekursiv-readdir- Modul verfügt über diese Funktionalität.
quelle
Ich habe die auf Promise basierende Antwort von Trevor Senior geändert , um mit Bluebird zu arbeiten
quelle
Zum Spaß gibt es hier eine Flow-basierte Version, die mit der Stream-Bibliothek von highland.js funktioniert. Es wurde von Victor Vu mitverfasst.
quelle
Verwenden Sie Versprechen ( Q ), um dies in einem funktionalen Stil zu lösen:
Es gibt ein Versprechen eines Arrays zurück, sodass Sie es wie folgt verwenden können:
quelle
Ich muss die Promise-basierte Schleiferbibliothek zur Liste hinzufügen .
quelle
Verwenden von Bluebird Versprechen.Coroutine:
quelle
Weil jeder sein eigenes schreiben sollte, habe ich eins gemacht.
walk (dir, cb, endCb) cb (Datei) endCb (err | null)
DRECKIG
quelle
Schauen Sie sich loaddir https://npmjs.org/package/loaddir an
npm install loaddir
Sie können
fileName
anstelle von verwenden,baseName
wenn Sie die Erweiterung auch benötigen.Ein zusätzlicher Bonus ist, dass auch die Dateien angezeigt und der Rückruf erneut aufgerufen wird. Es gibt unzählige Konfigurationsoptionen, um es extrem flexibel zu machen.
Ich habe den
guard
Edelstein in kurzer Zeit mit loaddir aus Rubin gemachtquelle
Das ist meine Antwort. Hoffe es kann jemandem helfen.
Mein Fokus liegt darauf, dass die Suchroutine an einer beliebigen Stelle anhalten kann und für eine gefundene Datei die relative Tiefe zum ursprünglichen Pfad angibt.
quelle
Hier ist eine rekursive Methode zum Abrufen aller Dateien einschließlich der Unterverzeichnisse.
quelle
Ein weiterer einfacher und hilfreicher
quelle
So verwende ich die Funktion nodejs fs.readdir, um ein Verzeichnis rekursiv zu durchsuchen.
Angenommen, Sie haben einen Pfad mit dem Namen '/ database' im Stammverzeichnis Ihres Knotenprojekts. Sobald dieses Versprechen gelöst ist, sollte es ein Array jeder Datei unter '/ database' ausspucken.
quelle