如何获取 Node.js 目录中所有文件的名称列表?

IT技术 javascript node.js directory-listing
2021-02-01 19:18:10

我正在尝试使用 Node.js 获取目录中存在的所有文件的名称列表。我想要一个文件名数组的输出。我怎样才能做到这一点?

6个回答

您可以使用fs.readdirfs.readdirSync方法。fs包含在 Node.js 核心中,因此无需安装任何东西。

文件读取目录

const testFolder = './tests/';
const fs = require('fs');

fs.readdir(testFolder, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});

fs.readdir同步

const testFolder = './tests/';
const fs = require('fs');

fs.readdirSync(testFolder).forEach(file => {
  console.log(file);
});

这两种方法的区别在于,第一种是异步的,因此您必须提供一个回调函数,该函数将在读取过程结束时执行。

第二个是同步的,它将返回文件名数组,但它将停止任何进一步的代码执行,直到读取过程结束。

我应该补充一点,您很可能应该使用 readdire,因为您不想在 node.js 中阻塞 IO。
2021-03-10 19:18:10
@Sancarn 您想尝试解析ls? 等到有人创建一些带有嵌入空格和换行符的文件名......
2021-03-14 19:18:10
注意:readdir还显示目录名称要过滤这些,请使用fs.stat(path, callback(err, stats))stats.isDirectory()
2021-04-02 19:18:10
2021-04-05 19:18:10
@ user3705055 除非您使用 gulp 读取源顺序相关文件的目录并将它们编译为单个可执行文件。
2021-04-09 19:18:10

IMO 执行此类任务的最便捷方法是使用glob工具。这是node.jsglob 包安装

npm install glob

然后使用通配符匹配文件名(示例取自包的网站

var glob = require("glob")

// options is optional
glob("**/*.js", options, function (er, files) {
  // files is an array of filenames.
  // If the `nonull` option is set, and nothing
  // was found, then files is ["**/*.js"]
  // er is an error object or null.
})

如果您打算使用globby,这里是一个示例,用于查找当前文件夹下的任何 xml 文件

var globby = require('globby');

const paths = await globby("**/*.xml");  
我已经用@NachoColoma 评论更新了答案并展示了如何使用它
2021-03-15 19:18:10
对于像我这样正在寻找使用 Promise 的 glob 实现的人,请查看 sindresorhus 的 globby:github.com/sindresorhus/globby
2021-03-19 19:18:10
这对我来说是最好的解决方案,因为我想比字符串比较更容易指定文件类型。谢谢。
2021-03-24 19:18:10
@Lanti:该glob.sync(pattern, [options])方法可能更易于使用,因为它只返回一个文件名数组,而不是使用回调。更多信息:github.com/isaacs/node-glob
2021-03-28 19:18:10
怎样才能得到glob自身之外的结果呢?例如。我想要console.log结果,但不在里面glob()
2021-03-29 19:18:10

不过,上面的答案并未对目录执行递归搜索。这是我为递归搜索所做的(使用node-walk : npm install walk

var walk    = require('walk');
var files   = [];

// Walker options
var walker  = walk.walk('./test', { followLinks: false });

walker.on('file', function(root, stat, next) {
    // Add this file to the list of files
    files.push(root + '/' + stat.name);
    next();
});

walker.on('end', function() {
    console.log(files);
});
fs.readdirSync 更好,是专门为此创建的本机替代方案。
2021-03-11 19:18:10
这是一个很棒的功能。快速提问:有没有一种快速的方法可以忽略某些目录?我想忽略以开头的目录.git
2021-03-28 19:18:10
OP 没有询问哪个 API 进行递归读取。在任何情况下,已接受的答案也可以作为进行递归阅读的基础。
2021-03-30 19:18:10
这是 walk github repo + 文档的链接:github.com/coolaj86/node-walk
2021-04-05 19:18:10
不幸的是, fs.readdirSync 不会进入子目录,除非您愿意编写自己的例程来做到这一点,您没有考虑到已经有 npm module可以解决这个问题。
2021-04-08 19:18:10

获取所有子目录中的文件

const fs=require('fs');

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}

console.log(getFiles('path/to/dir'))
它不必是 11k。这取决于在堆栈上放置了多少,并且此方法对堆栈有相当大的分配。
2021-03-12 19:18:10
@MathiasLykkegaardLorenzen 如果您的文件系统嵌套了 11k 个目录,那么您可能还有很多其他事情需要担心:p
2021-03-24 19:18:10
为什么if (typeof files_ === 'undefined') files_=[];你只需要做var files_ = files_ || [];而不是files_ = files_ || [];.
2021-03-26 19:18:10
这是一种递归方法。它不支持非常深的文件夹结构,这会导致堆栈溢出。
2021-03-26 19:18:10
您忘记var fs = require('fs');getFiles.
2021-04-03 19:18:10

这是一个仅使用本机fspathmodule的简单解决方案

// sync version
function walkSync(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdirSync(currentDirPath).forEach(function (name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walkSync(filePath, callback);
        }
    });
}

或异步版本(fs.readdir改为使用):

// async version with basic error handling
function walk(currentDirPath, callback) {
    var fs = require('fs'),
        path = require('path');
    fs.readdir(currentDirPath, function (err, files) {
        if (err) {
            throw new Error(err);
        }
        files.forEach(function (name) {
            var filePath = path.join(currentDirPath, name);
            var stat = fs.statSync(filePath);
            if (stat.isFile()) {
                callback(filePath, stat);
            } else if (stat.isDirectory()) {
                walk(filePath, callback);
            }
        });
    });
}

然后你只需调用(同步版本):

walkSync('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

或异步版本:

walk('path/to/root/dir', function(filePath, stat) {
    // do something with "filePath"...
});

不同之处在于节点在执行 IO 时如何阻塞。鉴于上面的 API 是相同的,您可以只使用异步版本来确保最佳性能。

但是,使用同步版本有一个优势。一旦遍历完成,就更容易执行一些代码,就像遍历之后的下一条语句一样。使用异步版本,您需要一些额外的方式来知道何时完成。也许首先创建所有路径的地图,然后枚举它们。对于简单的构建/实用程序脚本(与高性能 Web 服务器相比),您可以使用同步版本而不会造成任何损坏。

应该替换walkSyncwalk(filePath, callback);的行walkSync(filePath, callback);
2021-04-06 19:18:10
但是你仍然在使用 fs.statSync,它在异步版本中阻塞。你不应该使用 fs.stat 吗?
2021-04-09 19:18:10