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

res*_*ion 882 javascript directory-listing node.js

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

CMS*_*CMS 1209

您可以使用fs.readdirfs.readdirSync方法.

fs.readdir

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

fs.readdir(testFolder, (err, files) => {
  files.forEach(file => {
    console.log(file);
  });
});
Run Code Online (Sandbox Code Playgroud)

fs.readdirSync

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

fs.readdirSync(testFolder).forEach(file => {
  console.log(file);
});
Run Code Online (Sandbox Code Playgroud)

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

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

  • 注意:`readdir`也显示*目录名*.要过滤这些,请使用[`fs.stat(path,callback(err,stats))`](http://nodejs.org/docs/v0.3.1/api/fs.html#fs.stat)和[` stats.isDirectory()`](http://nodejs.org/docs/v0.3.1/api/fs.html#fs.Stats). (191认同)
  • @ user3705055除非你使用gulp读取源顺序依赖文件的目录并将它们编译成单个可执行文件. (5认同)
  • 我应该补充一点,你很可能应该使用readdire,因为你不想在节点中阻止IO. (3认同)
  • 对于[更新的承诺方法,请参阅我的回答](http://stackoverflow.com/a/37532027/124486). (3认同)
  • @Sancarn你想尝试解析`ls`的输出?等到有人创建一些带有嵌入空格和换行符的文件名...... (2认同)
  • 从 Node v10.10.0 开始,`readdir` 和 `readdirSync` 函数的 `withFileTypes` 选项与 `isDirectory()` 方法的组合可用于仅过滤目录中的文件 - [docs](https ://nodejs.org/api/fs.html#fs_class_fs_dirent) 和 [此处的示例](/sf/answers/3810798701/) (2认同)

KFL*_*KFL 184

IMO最方便的方法就是使用glob工具.这是node.js 的glob包.安装时

npm install glob
Run Code Online (Sandbox Code Playgroud)

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

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.
})
Run Code Online (Sandbox Code Playgroud)

  • @Lanti:`glob.sync(pattern,[options])`方法可能更容易使用,因为它只返回一个文件名数组,而不是使用回调.更多信息:https://github.com/isaacs/node-glob (12认同)
  • 这对我来说是最好的解决方案,因为我想比字符串比较更容易指定文件类型.谢谢. (4认同)
  • 对于像我这样使用 Promise 寻找 glob 实现的人,请查看 sindresorhus 的 globby:https://github.com/sindresorhus/globby (4认同)

Rub*_*Tan 176

上面的答案虽然没有对目录进行递归搜索.下面是我做了一个递归搜索(使用节点行走: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);
});
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,fs.readdirSync不会进入子目录,除非你愿意编写自己的例程来做到这一点,你没有给出已经有npm模块来解决这个问题. (36认同)
  • 这是一个指向walk github repo + docs的链接:https://github.com/coolaj86/node-walk (6认同)
  • fs.readdirSync更好,专门为此创建的本机替代品. (3认同)

Tit*_*100 85

获取所有子目录中的文件

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'))
Run Code Online (Sandbox Code Playgroud)

  • 它显然确实返回了一个文件列表. (7认同)
  • 为什么`if(typeof files_ ==='undefined')文件_ = [];`?你只需要做`var files_ = files_ || [];`而不是`files_ = files_ || [];`. (4认同)
  • 你忘了在`getFiles`的开头添加`var fs = require('fs');`. (4认同)
  • @MathiasLykkegaardLorenzen 如果你有一个嵌套了 11k 目录的文件系统,你可能还有很多其他事情需要担心:p (4认同)

Ali*_*Ali 59

这是一个只使用本机fspath模块的简单解决方案:

// 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);
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

或异步版本(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);
            }
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

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

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

或异步版本:

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

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

但是,使用同步版本有一个优点.步行完成后,执行某些代码会更容易,如步行后的下一个语句.使用异步版本,您需要一些额外的方法来了解何时完成.也许首先创建所有路径的地图,然后枚举它们.对于简单的build/util脚本(与高性能Web服务器相比),您可以使用同步版本而不会造成任何损坏.

  • 但是你仍然在异步版本中使用fs.statSync阻塞.你不应该使用fs.stat吗? (3认同)

Eva*_*oll 23

在ES7中使用Promise

与mz/fs异步使用

mz模块提供了核心节点库的promisified版本.使用它们很简单.首先安装库...

npm install mz
Run Code Online (Sandbox Code Playgroud)

然后...

const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
  .catch(err => console.error(err));
Run Code Online (Sandbox Code Playgroud)

或者,您可以在ES7中的异步函数中编写它们:

async function myReaddir () {
  try {
    const file = await fs.readdir('./myDir/');
  }
  catch (err) { console.error( err ) }
};
Run Code Online (Sandbox Code Playgroud)

递归列表的更新

一些用户已经指定了查看递归列表的愿望(虽然不在问题中)...使用fs-promise.这是一个薄薄的包装mz.

npm install fs-promise;
Run Code Online (Sandbox Code Playgroud)

然后...

const fs = require('fs-promise');
fs.walk('./myDir').then(
    listing => listing.forEach(file => console.log(file.path))
).catch(err => console.error(err));
Run Code Online (Sandbox Code Playgroud)

  • fs.walk从fs-promise中删除,因为它不支持fs(https://github.com/kevinbeaty/fs-promise/issues/28) (4认同)

Hun*_*yan 19

依赖.

var fs = require('fs');
var path = require('path');
Run Code Online (Sandbox Code Playgroud)

定义.

// String -> [String]
function fileList(dir) {
  return fs.readdirSync(dir).reduce(function(list, file) {
    var name = path.join(dir, file);
    var isDir = fs.statSync(name).isDirectory();
    return list.concat(isDir ? fileList(name) : [name]);
  }, []);
}
Run Code Online (Sandbox Code Playgroud)

用法.

var DIR = '/usr/local/bin';

// 1. List all files in DIR
fileList(DIR);
// => ['/usr/local/bin/babel', '/usr/local/bin/bower', ...]

// 2. List all file names in DIR
fileList(DIR).map((file) => file.split(path.sep).slice(-1)[0]);
// => ['babel', 'bower', ...]
Run Code Online (Sandbox Code Playgroud)

请注意,这fileList太乐观了.对于任何严重的,添加一些错误处理.


bnp*_*887 16

从Node v10.10.0开始,可以将new withFileTypes选项用于此功能,fs.readdirfs.readdirSync与该dirent.isDirectory()功能结合使用以过滤目录中的文件名。看起来像这样:

fs.readdirSync('./dirpath', {withFileTypes: true})
.filter(item => !item.isDirectory())
.map(item => item.name)
Run Code Online (Sandbox Code Playgroud)

返回的数组的形式为:

['file1.txt', 'file2.txt', 'file3.txt']
Run Code Online (Sandbox Code Playgroud)

fs.Dirent类的文档

  • 2022 年也是如此! (9认同)
  • 这是人们在 2020 年搜索的内容 - 应该被“固定” (7认同)
  • 到目前为止,这是最好的答案! (5认同)
  • 太好了,这回答了有关“文件名”的问题 (2认同)

a.b*_*eri 16

我从你的问题中假设你不想要目录名称,只需要文件。

目录结构示例

animals
??? all.jpg
??? mammals
?   ??? cat.jpg
?   ??? dog.jpg
??? insects
    ??? bee.jpg
Run Code Online (Sandbox Code Playgroud)

Walk 功能

积分去贾斯汀·迈尔这个要点

如果您只需要一组文件路径,请使用return_object: false

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

async function walk(dir) {
    let files = await fs.readdir(dir);
    files = await Promise.all(files.map(async file => {
        const filePath = path.join(dir, file);
        const stats = await fs.stat(filePath);
        if (stats.isDirectory()) return walk(filePath);
        else if(stats.isFile()) return filePath;
    }));

    return files.reduce((all, folderContents) => all.concat(folderContents), []);
}
Run Code Online (Sandbox Code Playgroud)

用法

async function main() {
   console.log(await walk('animals'))
}
Run Code Online (Sandbox Code Playgroud)

输出

[
  "/animals/all.jpg",
  "/animals/mammals/cat.jpg",
  "/animals/mammals/dog.jpg",
  "/animals/insects/bee.jpg"
];
Run Code Online (Sandbox Code Playgroud)

  • @justmaier 和 a.barbieri - 感谢您的代码和答案! (2认同)

aak*_*dev 16

它只有两行代码:

fs=require('fs')
fs.readdir("./img/", (err,filename)=>console.log(filename))
Run Code Online (Sandbox Code Playgroud)

图像: 阿卡什4开发者


Tyl*_*ong 14

你不是说你想要递归地做,所以我假设你只需要目录的直接子项.

示例代码:

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

fs.readdirSync('your-directory-path')
  .filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
Run Code Online (Sandbox Code Playgroud)


小智 14

如果有人还在搜索这个,我会这样做:

import fs from 'fs';
import path from 'path';

const getAllFiles = dir =>
    fs.readdirSync(dir).reduce((files, file) => {
        const name = path.join(dir, file);
        const isDirectory = fs.statSync(name).isDirectory();
        return isDirectory ? [...files, ...getAllFiles(name)] : [...files, name];
    }, []);
Run Code Online (Sandbox Code Playgroud)

它的工作对我来说非常好

  • @MdMazedulIslamKhan 这里使用的 `...` 称为扩展语法。它的基本作用是获取数组内的所有对象并将其“传播”到新数组中。在这种情况下,“files”数组内的所有条目都将与递归调用返回的所有值一起添加到返回值中。您可以在这里参考扩展语法:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax (2认同)

Ces*_*las 13

我的单行代码:

const fs = require("fs")
const path = 'somePath/'

const filesArray = fs.readdirSync(path).filter(file => fs.lstatSync(path+file).isFile())
Run Code Online (Sandbox Code Playgroud)


Edu*_*omo 9

装载fs:

const fs = require('fs');
Run Code Online (Sandbox Code Playgroud)

读取文件异步:

fs.readdir('./dir', function (err, files) {
    // "files" is an Array with files names
});
Run Code Online (Sandbox Code Playgroud)

读取文件同步:

var files = fs.readdirSync('./dir');
Run Code Online (Sandbox Code Playgroud)


小智 8

试试这个,它对我有用

import fs from "fs/promises";

const path = "path/to/folder";

export const readDir = async function readDir(path) {

    const files = await fs.readdir(path);

    // array of file names
    console.log(files);
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。不需要“npm install”,它可以与“esm import”和“async/await”一起使用。对于完整的示例,您应该将其包装在一个函数中。 (2认同)

Yas*_*Yas 6

获取sorted文件名。您可以基于特定的过滤结果,extension例如'.txt''.jpg'等等。

import * as fs from 'fs';
import * as Path from 'path';

function getFilenames(path, extension) {
    return fs
        .readdirSync(path)
        .filter(
            item =>
                fs.statSync(Path.join(path, item)).isFile() &&
                (extension === undefined || Path.extname(item) === extension)
        )
        .sort();
}
Run Code Online (Sandbox Code Playgroud)


Pau*_*ood 6

这是一个 TypeScript,可选递归,可选错误日志和异步解决方案。您可以为要查找的文件名指定正则表达式。

我使用过fs-extra,因为它对fs.

import * as FsExtra from 'fs-extra'

/**
 * Finds files in the folder that match filePattern, optionally passing back errors .
 * If folderDepth isn't specified, only the first level is searched. Otherwise anything up
 * to Infinity is supported.
 *
 * @static
 * @param {string} folder The folder to start in.
 * @param {string} [filePattern='.*'] A regular expression of the files you want to find.
 * @param {(Error[] | undefined)} [errors=undefined]
 * @param {number} [folderDepth=0]
 * @returns {Promise<string[]>}
 * @memberof FileHelper
 */
public static async findFiles(
    folder: string,
    filePattern: string = '.*',
    errors: Error[] | undefined = undefined,
    folderDepth: number = 0
): Promise<string[]> {
    const results: string[] = []

    // Get all files from the folder
    let items = await FsExtra.readdir(folder).catch(error => {
        if (errors) {
            errors.push(error) // Save errors if we wish (e.g. folder perms issues)
        }

        return results
    })

    // Go through to the required depth and no further
    folderDepth = folderDepth - 1

    // Loop through the results, possibly recurse
    for (const item of items) {
        try {
            const fullPath = Path.join(folder, item)

            if (
                FsExtra.statSync(fullPath).isDirectory() &&
                folderDepth > -1)
            ) {
                // Its a folder, recursively get the child folders' files
                results.push(
                    ...(await FileHelper.findFiles(fullPath, filePattern, errors, folderDepth))
                )
            } else {
                // Filter by the file name pattern, if there is one
                if (filePattern === '.*' || item.search(new RegExp(filePattern, 'i')) > -1) {
                    results.push(fullPath)
                }
            }
        } catch (error) {
            if (errors) {
                errors.push(error) // Save errors if we wish
            }
        }
    }

    return results
}
Run Code Online (Sandbox Code Playgroud)


Mah*_*esh 6

盒子外面

如果您想要一个具有开箱即用的目录结构对象,我强烈建议您检查directory-tree

假设你有这个结构:

photos
?   june
?   ??? windsurf.jpg
??? january
    ??? ski.png
    ??? snowboard.jpg
Run Code Online (Sandbox Code Playgroud)
photos
?   june
?   ??? windsurf.jpg
??? january
    ??? ski.png
    ??? snowboard.jpg
Run Code Online (Sandbox Code Playgroud)

将返回:

{
  path: "photos",
  name: "photos",
  size: 600,
  type: "directory",
  children: [
    {
      path: "photos/june",
      name: "june",
      size: 400,
      type: "directory",
      children: [
        {
          path: "photos/june/windsurf.jpg",
          name: "windsurf.jpg",
          size: 400,
          type: "file",
          extension: ".jpg"
        }
      ]
    },
    {
      path: "photos/january",
      name: "january",
      size: 200,
      type: "directory",
      children: [
        {
          path: "photos/january/ski.png",
          name: "ski.png",
          size: 100,
          type: "file",
          extension: ".png"
        },
        {
          path: "photos/january/snowboard.jpg",
          name: "snowboard.jpg",
          size: 100,
          type: "file",
          extension: ".jpg"
        }
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

自定义对象

否则,如果您想使用自定义设置创建目录树对象,请查看以下代码段。在这个代码和框上可以看到一个活生生的例子。

const dirTree = require("directory-tree");
const tree = dirTree("/path/to/photos");
Run Code Online (Sandbox Code Playgroud)

然后你可以简单地做:

{
  path: "photos",
  name: "photos",
  size: 600,
  type: "directory",
  children: [
    {
      path: "photos/june",
      name: "june",
      size: 400,
      type: "directory",
      children: [
        {
          path: "photos/june/windsurf.jpg",
          name: "windsurf.jpg",
          size: 400,
          type: "file",
          extension: ".jpg"
        }
      ]
    },
    {
      path: "photos/january",
      name: "january",
      size: 200,
      type: "directory",
      children: [
        {
          path: "photos/january/ski.png",
          name: "ski.png",
          size: 100,
          type: "file",
          extension: ".png"
        },
        {
          path: "photos/january/snowboard.jpg",
          name: "snowboard.jpg",
          size: 100,
          type: "file",
          extension: ".jpg"
        }
      ]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)


Rap*_*nah 6

使用平面地图

\n
function getFiles(dir) {\n  return fs.readdirSync(dir).flatMap((item) => {\n    const path = `${dir}/${item}`;\n    if (fs.statSync(path).isDirectory()) {\n      return getFiles(path);\n    }\n\n    return path;\n  });\n}\n
Run Code Online (Sandbox Code Playgroud)\n

给定以下目录:

\n
dist\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 404.html\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app-AHOLRMYQ.js\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 img\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 demo.gif\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 start.png\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.html\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 sw.js\n
Run Code Online (Sandbox Code Playgroud)\n

用法:

\n
getFiles("dist")\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
[\n  \'dist/404.html\',\n  \'dist/app-AHOLRMYQ.js\',\n  \'dist/img/demo.gif\',\n  \'dist/img/start.png\',\n  \'dist/index.html\'\n]\n
Run Code Online (Sandbox Code Playgroud)\n


Ogg*_*nes 5

这是一个异步递归版本。

    function ( path, callback){
     // the callback gets ( err, files) where files is an array of file names
     if( typeof callback !== 'function' ) return
     var
      result = []
      , files = [ path.replace( /\/\s*$/, '' ) ]
     function traverseFiles (){
      if( files.length ) {
       var name = files.shift()
       fs.stat(name, function( err, stats){
        if( err ){
         if( err.errno == 34 ) traverseFiles()
    // in case there's broken symbolic links or a bad path
    // skip file instead of sending error
         else callback(err)
        }
        else if ( stats.isDirectory() ) fs.readdir( name, function( err, files2 ){
         if( err ) callback(err)
         else {
          files = files2
           .map( function( file ){ return name + '/' + file } )
           .concat( files )
          traverseFiles()
         }
        })
        else{
         result.push(name)
         traverseFiles()
        }
       })
      }
      else callback( null, result )
     }
     traverseFiles()
    }
Run Code Online (Sandbox Code Playgroud)

  • 养成在语句末尾添加分号的习惯。否则你不能缩小代码。尽管如此,感谢您急需的异步贡献。 (4认同)
  • @user2867288但是既然ASI存在,我们就可以使用它,不是吗?我使用 eslint 和 prettier 定期保存代码,并且分号插入不是问题。 (3认同)
  • HAHAHAHA 这不是规范的一部分,只是一些随机的人称他们喜欢的 linting 风格“standardjs”。分号是一种很好的做法,尤其是在 Javascript 中,以保持代码清晰。否则你和你的团队必须记住【自动分号插入】的规则(https://dev.to/promhize/what-you-need-to-know-about-javascripts-automatic-semi-colon-insertion-78a) ,而且我知道至少我工作的普通 JS 开发人员并没有那么勤奋。 (2认同)

A T*_*A T 5

采用@Hunan-Rostomyan 的一般方法,使其更加简洁并增加了excludeDirs论点。用 扩展很简单includeDirs,只需遵循相同的模式:

import * as fs from 'fs';
import * as path from 'path';

function fileList(dir, excludeDirs?) {
    return fs.readdirSync(dir).reduce(function (list, file) {
        const name = path.join(dir, file);
        if (fs.statSync(name).isDirectory()) {
            if (excludeDirs && excludeDirs.length) {
                excludeDirs = excludeDirs.map(d => path.normalize(d));
                const idx = name.indexOf(path.sep);
                const directory = name.slice(0, idx === -1 ? name.length : idx);
                if (excludeDirs.indexOf(directory) !== -1)
                    return list;
            }
            return list.concat(fileList(name, excludeDirs));
        }
        return list.concat([name]);
    }, []);
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
Run Code Online (Sandbox Code Playgroud)


Man*_*anu 5

如果有人,我的 2 美分:

只想从项目的本地子文件夹中列出文件名(不包括目录)

  • ? 没有额外的依赖
  • ? 1 功能
  • ? 规范化路径(Unix 与 Windows)
const fs = require("fs");
const path = require("path");

/**
 * @param {string} relativeName "resources/foo/goo"
 * @return {string[]}
 */
const listFileNames = (relativeName) => {
  try {
    const folderPath = path.join(process.cwd(), ...relativeName.split("/"));
    return fs
      .readdirSync(folderPath, { withFileTypes: true })
      .filter((dirent) => dirent.isFile())
      .map((dirent) => dirent.name.split(".")[0]);
  } catch (err) {
    // ...
  }
};

Run Code Online (Sandbox Code Playgroud)
README.md
package.json
resources
 |-- countries
    |-- usa.yaml
    |-- japan.yaml
    |-- gb.yaml
    |-- provinces
       |-- .........


listFileNames("resources/countries") #=> ["usa", "japan", "gb"]
Run Code Online (Sandbox Code Playgroud)