如何获取Node.js中目录中所有文件的名称列表?
我试图使用Node.js获取目录中所有文件的名称列表。 我想要的输出是一个文件名数组。 我该怎么做?
您可以使用fs.readdir
或fs.readdirSync
方法。
fs.readdir
const testFolder = './tests/'; const fs = require('fs'); fs.readdir(testFolder, (err, files) => { files.forEach(file => { console.log(file); }); })
fs.readdirSync
const testFolder = './tests/'; const fs = require('fs'); fs.readdirSync(testFolder).forEach(file => { console.log(file); })
这两种方法的区别在于第一种方法是asynchronous的,所以你必须提供一个callback函数,当读取过程结束时执行。
第二个是同步的,它将返回文件名数组,但是它会停止你的代码的进一步执行,直到读取过程结束。
上面的答案不会执行recursionsearch到目录。 这是我做了recursionsearch(使用节点行走 : 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); });
海事组织做这样的任务最方便的方法是使用glob工具。 这是一个node.js的glob包 。 用…安装
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. })
获取所有子目录中的文件
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'))
这是一个简单的解决scheme,只使用本机fs
和path
模块:
// 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); } }); }
或asynchronous版本(使用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"... });
或asynchronous版本:
walk('path/to/root/dir', function(filePath, stat) { // do something with "filePath"... });
不同之处在于节点在执行IO时如何阻塞。 鉴于上面的API是相同的,你可以使用asynchronous版本,以确保最大的性能。
但是使用同步版本有一个好处。 步行完成后,执行一些代码就更容易了,就像在步行之后的下一个语句中一样。 使用asynchronous版本,您需要一些额外的方式来了解何时完成。 也许先创build一个所有path的地图,然后枚举它们。 对于简单的构build/实用脚本(vs高性能Web服务器),您可以使用同步版本而不会造成任何损害。
使用承诺与ES7
asynchronous使用mz / fs
mz
模块提供核心节点库的promisified版本。 使用它们很简单。 首先安装库…
npm install mz
然后…
const fs = require('mz/fs'); fs.readdir('./myDir').then(listing => console.log(listing)) .catch(err => console.error(err));
或者,您可以在ES7中的asynchronous函数中编写它们:
async function myReaddir () { try { const file = await fs.readdir('./myDir/'); } catch (err) { console.error( err ) } };
更新recursion列表
一些用户已经指定了看到recursion列表的愿望(尽pipe不是在问题中)…使用fs-promise
。 这是围绕mz
的薄包装。
npm install fs-promise;
然后…
const fs = require('fs-promise'); fs.walk('./myDir').then( listing => listing.forEach(file => console.log(file.path)) ).catch(err => console.error(err));
依赖。
var fs = require('fs'); var path = require('path');
定义。
// 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]); }, []); }
用法。
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', ...]
请注意, fileList
过于乐观。 对于任何严重的事情,添加一些error handling
你不要说你想recursion的做,所以我假设你只需要直接的子目录。
示例代码:
const fs = require('fs'); const path = require('path'); fs.readdirSync('your-directory-path') .filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
这是一个asynchronousrecursion版本。
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() }
采取@湖南 – 俄罗斯方丹的一般做法,使其更加简明扼要,并添加了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]); }, []); }
用法示例:
console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
加载fs
:
const fs = require('fs');
读取文件asynchronous :
fs.readdir('./dir', function (err, files) { // "files" is an Array with files names });
读文件同步 :
var files = fs.readdirSync('./dir');
只是一个问题:如果您打算对目录中的每个文件执行操作,请尝试vinyl-fs (stream量构build系统使用gulp )。
我做了一个节点模块来自动执行这个任务: mddir
用法
节点mddir“../relative/path/”
要安装:npm install mddir -g
为当前目录生成降价:mddir
为任何绝对path生成:mddir / absolute / path
为相对path生成:mddir〜/ Documents / whatever。
md文件在您的工作目录中生成。
目前忽略node_modules和.git文件夹。
故障排除
如果您收到错误“node \ r:没有这样的文件或目录”,问题是您的操作系统使用不同的行尾,而mddir无法parsing它们,而没有明确地将行结束样式设置为Unix。 这通常影响Windows,但也有一些版本的Linux。 将行结尾设置为Unix样式必须在mddir npm全局bin文件夹中执行。
行结尾修复
获取npm bin文件夹path:
npm config get prefix
镉进入该文件夹
brew安装dos2unix
dos2unix lib / node_modules / mddir / src / mddir.js
这将行结束符转换为Unix而不是DOS
然后像以下那样正常运行:node mddir“../relative/path/”。
生成markdown文件结构的例子'directoryList.md'
|-- .bowerrc |-- .jshintrc |-- .jshintrc2 |-- Gruntfile.js |-- README.md |-- bower.json |-- karma.conf.js |-- package.json |-- app |-- app.js |-- db.js |-- directoryList.md |-- index.html |-- mddir.js |-- routing.js |-- server.js |-- _api |-- api.groups.js |-- api.posts.js |-- api.users.js |-- api.widgets.js |-- _components |-- directives |-- directives.module.js |-- vendor |-- directive.draganddrop.js |-- helpers |-- helpers.module.js |-- proprietary |-- factory.actionDispatcher.js |-- services |-- services.cardTemplates.js |-- services.cards.js |-- services.groups.js |-- services.posts.js |-- services.users.js |-- services.widgets.js |-- _mocks |-- mocks.groups.js |-- mocks.posts.js |-- mocks.users.js |-- mocks.widgets.js
function getFilesRecursiveSync(dir, fileList, optionalFilterFunction) { if (!fileList) { grunt.log.error("Variable 'fileList' is undefined or NULL."); return; } var files = fs.readdirSync(dir); for (var i in files) { if (!files.hasOwnProperty(i)) continue; var name = dir + '/' + files[i]; if (fs.statSync(name).isDirectory()) { getFilesRecursiveSync(name, fileList, optionalFilterFunction); } else { if (optionalFilterFunction && optionalFilterFunction(name) !== true) continue; fileList.push(name); } } }