我想使用具有递归的readdir(async)查找特定扩展名的文件

问题描述 投票:1回答:1

我是Node js的新手,我有一项任务是通过扩展名为搜索文件创建cli实用程序。我写这个

const fs = require('fs');  
const path = require('path'); 

let pathSupplied = './';
let extFilter = 'html';

function extension(element) {
    let extName = path.extname(element);
    return extName === '.' + extFilter;
};

let walk = function (dir, done) {
    let result = []
    fs.readdir(dir, function (err, list) {
        list.forEach((item) => {
            let itemPath = path.join(dir, item);
            fs.stat(itemPath, (e, stats) => {
                console.log(itemPath);
                if (stats.isDirectory()) {
                    walk(itemPath);
                } else {
                    list.filter(extension).forEach(function (value) {
                        console.log(value);
                    });
                }
            });
        });
    })
}

它有效,但不是我想要的方式。在输出中,我得到了带有html扩展名的文件,但是它们是重复的。我怎样才能解决这个问题?以及如何将结果写入数组?

javascript node.js recursion filesystems
1个回答
0
投票

这很自然地使用promise和async/await,因为它使编码变得非常简单。我建议创建一个通用的walk()函数,您可以将其传递给该回调函数,该回调函数将针对层次结构中的每个文件被调用。然后,您可以使用该回调来收集所需的任何结果。

这里是通用行走功能:

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

async function walk(dir, callback, results = []) {
    let files = await fsp.readdir(dir, {withFileTypes: true});
    let dirs = [];
    for (let file of files) {
        let fullPath = path.join(dir, file.name);
        if (file.isFile()) {
            let r = await callback(fullPath);
            if (r !== undefined) {
                results.push(r);
            }
        } else if (file.isDirectory()) {
            // save this until we're done with files
            dirs.push(fullPath);
        }
    }
    for (let d of dirs) {
        await walk(d, callback, results);
    }
    return results;
}

然后,您可以像这样使用它来累积具有特定扩展名的文件:

const targetExt = ".html";
const someTopDir = "D:/somepath/somedir";

walk(someTopDir, function(file) {
    if (path.extname(file) === targetExt) {
        return file;
    }
}).then(results => {
    console.log(results);
}).catch(err => {
    console.log(err);
});

有关实现的一些注意事项:

  1. 如果返回一个promise,则回调可以是异步的。
  2. 这使用来自最新版本的node.js的fsPromises API来实现许多fs库函数的承诺版本。
  3. [这利用了withFileTypes的较新readdir()选项,该选项在每个文件上保存一个异步操作以测试它是否是目录
  4. 链中任何地方的任何错误都将中止整个链并冒泡给呼叫者,因为它被拒绝了。
  5. walk()函数返回一个承诺,该承诺将解析为回调返回的值数组。这意味着您可以像.map().filter()的组合一样使用它。输入数组是目录层次结构中所有文件的数组。如果您的回调返回undefined,则该特定文件的输出中不存在任何内容(类似于.filter())。如果回调返回的不是undefined,则该返回值将在输出数组中(类似于.map())。在此特定的回调实现中,它检查文件扩展名是否为匹配的扩展名。如果是这样,它将仅返回该文件名(以将其包含在输出中)。如果不是,它将不返回任何内容(这意味着返回值为undefined),因此该文件的输出中不包含任何内容。实际上,它允许您同时执行.map().filter()
© www.soinside.com 2019 - 2024. All rights reserved.