391 Stimmen

Node.js fs.readdir rekursive Verzeichnissuche

Irgendwelche Ideen für eine asynchrone Verzeichnissuche mit fs.readdir? Mir ist klar, dass wir eine Rekursion einführen und die Funktion read directory mit dem nächsten zu lesenden Verzeichnis aufrufen könnten, aber ich bin ein wenig besorgt, dass es nicht asynchron ist...

Irgendwelche Ideen? Ich habe mir angesehen node-walk was großartig ist, aber mir nicht nur die Dateien in einem Array liefert, wie es readdir tut. Obwohl

Ich suche eine Ausgabe wie...

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

7voto

Gander Punkte 1636

qwtel 's Antwort Variante, in TypScript

import { resolve } from 'path';
import { readdir } from 'fs/promises';

async function* getFiles(dir: string): AsyncGenerator<string> {
    const entries = await readdir(dir, { withFileTypes: true });
    for (const entry of entries) {
        const res = resolve(dir, entry.name);
        if (entry.isDirectory()) {
            yield* getFiles(res);
        } else {
            yield res;
        }
    }
}

6voto

Kabeer Jaffri Punkte 562

Einfaches, asynchrones Versprechen

const fs = require('fs/promises');
const getDirRecursive = async (dir) => {
    try {
        const items = await fs.readdir(dir);
        let files = [];
        for (const item of items) {
            if ((await fs.lstat(`${dir}/${item}`)).isDirectory()) files = [...files, ...(await getDirRecursive(`${dir}/${item}`))];
            else files.push({file: item, path: `${dir}/${item}`, parents: dir.split("/")});
        }
        return files;
    } catch (e) {
        return e
    }
};

Verwendung: await getDirRecursive("./public");

5voto

mpen Punkte 253762

Mit async/await sollte dies funktionieren:

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

Sie können verwenden bluebird.Promisify oder dies:

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

Node 8+ hat Promisify eingebaut

Siehe meine andere Antwort für einen Generatoransatz, der noch schneller zu Ergebnissen führen kann.

4voto

nickool Punkte 794

Eine Bibliothek namens Filehound ist eine weitere Option. Sie durchsucht rekursiv ein bestimmtes Verzeichnis (standardmäßig das Arbeitsverzeichnis). Sie unterstützt verschiedene Filter, Rückrufe, Versprechen und Sync-Suchen.

Suchen Sie zum Beispiel im aktuellen Arbeitsverzeichnis nach allen Dateien (unter Verwendung von Rückrufen):

const Filehound = require('filehound');

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

Oder verspricht und ein bestimmtes Verzeichnis angibt:

const Filehound = require('filehound');

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

In der Dokumentation finden Sie weitere Anwendungsfälle und Beispiele für die Nutzung: https://github.com/nspragg/filehound

Haftungsausschluss: Ich bin der Autor.

4voto

recidive Punkte 388

Ich habe dies kürzlich programmiert und dachte, es wäre sinnvoll, dies hier zu teilen. Der Code macht Gebrauch von der asynchrone Bibliothek .

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

Sie können ihn wie folgt verwenden:

scan('/some/dir', '.ext', function(err, files) {
  // Do something with files that ends in '.ext'.
  console.log(files);
});

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X