Асинхронное и рекурсивное сканирование каталогов, для списка файлов в Nodejs и Expressjs - PullRequest
0 голосов
/ 13 июня 2019

В этом Expressjs файле маршрута я пытаюсь (рекурсивно) получить все файлы JSON в каталоге . / Data .

На самом деле я могу console.log файл, где вы можете увидеть метку , но я не могу найти способ, чтобы отправить весь полный набор путей к представлению после завершения асинхронного процесса.

Некоторая помощь будет очень признательна.

Это данные . / Data структура:

--- dir1
    `-- json1.json
    `-- json2.json
--- dir2
    `-- json3.json
--- dir3
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;

1 Ответ

1 голос
/ 13 июня 2019

Вы можете упростить задачу, если вы обещаете функции 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;
}

Приведенный выше код был протестирован в узле v10.14.1.

Затем вы можете использовать его так же, как и вы:

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

К вашему сведению, для модуля fs существует более новый (все еще экспериментальный) API, основанный на обещаниях.Вы можете использовать это следующим образом:

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

Обратите внимание, что эта новая версия также использует новую опцию withFileTypes, которая избавляет от необходимости вызывать stat() для каждого файла.

...