node.js fs.readdir recursive directory search

前端 未结 30 1532
醉酒成梦
醉酒成梦 2020-11-22 15:55

Any ideas on an async directory search using fs.readdir? I realise that we could introduce recursion and call the read directory function with the next directory to read, bu

相关标签:
30条回答
  • 2020-11-22 16:08

    Check out the final-fs library. It provides a readdirRecursive function:

    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
        });
    
    0 讨论(0)
  • 2020-11-22 16:09

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

    You can use fileName instead of baseName if you need the extension as well.

    An added bonus is that it will watch the files as well and call the callback again. There are tons of configuration options to make it extremely flexible.

    I just remade the guard gem from ruby using loaddir in a short while

    0 讨论(0)
  • 2020-11-22 16:10

    Async

    const fs = require('fs')
    const path = require('path')
    
    const readdir = (p, done, a = [], i = 0) => fs.readdir(p, (e, d = []) =>
      d.map(f => readdir(a[a.push(path.join(p, f)) - 1], () =>
        ++i == d.length && done(a), a)).length || done(a))
    
    readdir(__dirname, console.log)
    

    Sync

    const fs = require('fs')
    const path = require('path')
    
    const readdirSync = (p, a = []) => {
      if (fs.statSync(p).isDirectory())
        fs.readdirSync(p).map(f => readdirSync(a[a.push(path.join(p, f)) - 1], a))
      return a
    }
    
    console.log(readdirSync(__dirname))
    

    Async readable

    function readdir (currentPath, done, allFiles = [], i = 0) {
      fs.readdir(currentPath, function (e, directoryFiles = []) {
        if (!directoryFiles.length)
          return done(allFiles)
        directoryFiles.map(function (file) {
          var joinedPath = path.join(currentPath, file)
          allFiles.push(joinedPath)
          readdir(joinedPath, function () {
            i = i + 1
            if (i == directoryFiles.length)
              done(allFiles)}
          , allFiles)
        })
      })
    }
    
    readdir(__dirname, console.log)
    

    Note: both versions will follow symlinks (same as the original fs.readdir)

    0 讨论(0)
  • 2020-11-22 16:11

    If you want to use an npm package, wrench is pretty good.

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

    EDIT (2018):
    Anyone reading through in recent time: The author deprecated this package in 2015:

    wrench.js is deprecated, and hasn't been updated in quite some time. I heavily recommend using fs-extra to do any extra filesystem operations.

    0 讨论(0)
  • 2020-11-22 16:13

    Using async/await, this should work:

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

    You can use bluebird.Promisify or this:

    /**
     * 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+ has Promisify built-in

    See my other answer for a generator approach that can give results even faster.

    0 讨论(0)
  • 2020-11-22 16:14

    Here's a recursive method of getting all files including subdirectories.

    const FileSystem = require("fs");
    const Path = require("path");
    
    //...
    
    function getFiles(directory) {
        directory = Path.normalize(directory);
        let files = FileSystem.readdirSync(directory).map((file) => directory + Path.sep + file);
    
        files.forEach((file, index) => {
            if (FileSystem.statSync(file).isDirectory()) {
                Array.prototype.splice.apply(files, [index, 1].concat(getFiles(file)));
            }
        });
    
        return files;
    }
    
    0 讨论(0)
提交回复
热议问题