异步和递归目录扫描,用于 Nodejs 和 Expressjs 中的文件列表

ant*_*zio 3 asynchronous fs node.js express es6-promise

在此Expressjs路由文件中,我尝试(递归地)获取./data目录内的所有 JSON 文件。

实际上,我可以在此处console.log文件,您可以看到A Mark,但我找不到在异步内容完成后将整组路径发送到视图的方法。

一些帮助将非常感激。

这是数据./数据结构:

--- dir1
    `-- json1.json
    `-- json2.json
--- dir2
    `-- json3.json
--- dir3
Run Code Online (Sandbox Code Playgroud)
const express = require('express'),
    router = express.Router(),
    fs = require('fs'),
    path = require('path')
    ;

let scan = function (directoryName = './data') {

    return new Promise((resolve, reject) => {

        fs.readdir(directoryName, function (err, files) {
            if (err) reject(err);

            files.map((currentValue, index, arr) => {
                let fullPath = path.join(directoryName, currentValue);

                fs.stat(fullPath, function (err, stat) {
                    if (err) reject(err);

                    if (stat.isDirectory()) {
                        scan(fullPath);
                    } else {
                        console.log(currentValue); <= (A mark)
                        //resolve();
                    }
                });
            });
        });
    })
};


router.get('/', (req, res, next) => {
  scan()
        .then(data => res.render('list', {
            title: 'List',
            data: data
        }))
        .catch(next);
});

module.exports = router;
Run Code Online (Sandbox Code Playgroud)

jfr*_*d00 9

fs如果您承诺正在使用的函数,以便所有异步逻辑都是承诺,然后使用 async/await 来帮助您序列化控制流,则可以大大简化任务。

这是一种方法:

const promisify = require('util').promisify;
const path = require('path');
const fs = require('fs');
const readdirp = promisify(fs.readdir);
const statp = promisify(fs.stat);

async function scan(directoryName = './data', results = []) {
    let files = await readdirp(directoryName);
    for (let f of files) {
        let fullPath = path.join(directoryName, f);
        let stat = await statp(fullPath);
        if (stat.isDirectory()) {
            await scan(fullPath, results);
        } else {
            results.push(fullPath);
        }
    }
    return results;
}
Run Code Online (Sandbox Code Playgroud)

以上代码在node v10.14.1中测试。

然后您可以像以前一样使用它:

router.get('/', (req, res, next) => {
  scan().then(data => res.render('list', {
      title: 'List',
      data: data
   })).catch(next);
});
Run Code Online (Sandbox Code Playgroud)

仅供参考,该模块有一个更新的(仍是实验性的)基于承诺的 API fs。你可以像这样使用它:

const path = require('path');
const fsp = require('fs').promises;

async function scan2(directoryName = './data', results = []) {
    let files = await fsp.readdir(directoryName, {withFileTypes: true});
    for (let f of files) {
        let fullPath = path.join(directoryName, f.name);
        if (f.isDirectory()) {
            await scan2(fullPath, results);
        } else {
            results.push(fullPath);
        }
    }
    return results;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这个新版本还使用了新withFileTypes选项,无需调用stat()每个文件。