我正在尝试使用 Node.js 获取目录中存在的所有文件的名称列表。我想要一个文件名数组的输出。我怎样才能做到这一点?
fs.readdir
有效,但不能使用像 ls /tmp/*core*
这样的文件名 glob 模式。查看 github.com/isaacs/node-glob。 Globs 甚至可以在子目录中搜索。
readdir-recursive
模块,但如果您也在寻找子目录中的文件名
您可以使用 fs.readdir
或 fs.readdirSync
方法。 fs
包含在 Node.js 核心中,因此无需安装任何东西。
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);
});
这两种方法的区别在于,第一种是异步的,所以你必须提供一个回调函数,在读取过程结束时执行。
第二个是同步的,它将返回文件名数组,但它将停止您的代码的任何进一步执行,直到读取过程结束。
IMO 执行此类任务的最便捷方式是使用 glob 工具。这是 node.js 的 glob package。安装
npm install glob
然后使用通配符匹配文件名(示例取自包的 website)
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");
glob
的结果?例如。我想要 console.log
结果,但不在 glob()
内?
glob.sync(pattern, [options])
方法可能更容易使用,因为它只是返回一个文件名数组,而不是使用回调。更多信息:github.com/isaacs/node-glob
上面的答案虽然不会对目录执行递归搜索。这是我为递归搜索所做的(使用 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);
});
.git
开头的目录
获取所有子目录中的文件
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'))
if (typeof files_ === 'undefined') files_=[];
?您只需要执行 var files_ = files_ || [];
而不是 files_ = files_ || [];
。
getFiles
的开头添加 var fs = require('fs');
。
从 Node v10.10.0 开始,可以将 fs.readdir
和 fs.readdirSync
的新 withFileTypes
选项与 dirent.isDirectory()
函数结合使用来过滤目录中的文件名。看起来像这样:
fs.readdirSync('./dirpath', {withFileTypes: true})
.filter(item => !item.isDirectory())
.map(item => item.name)
返回的数组格式为:
['file1.txt', 'file2.txt', 'file3.txt']
这是一个仅使用本机 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);
}
});
}
或异步版本(使用 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 是相同的,您可以只使用异步版本来确保最大性能。
然而,使用同步版本有一个优点。一旦 walk 完成就更容易执行一些代码,就像 walk 之后的下一条语句一样。使用异步版本,您将需要一些额外的方法来了解何时完成。也许首先创建所有路径的地图,然后枚举它们。对于简单的构建/实用脚本(与高性能 Web 服务器相比),您可以使用同步版本而不会造成任何损坏。
walkSync
中的行从 walk(filePath, callback);
替换为 walkSync(filePath, callback);
在 ES7 中使用 Promise
与 mz/fs 异步使用
mz
模块提供核心节点库的承诺版本。使用它们很简单。首先安装库...
npm install mz
然后...
const fs = require('mz/fs');
fs.readdir('./myDir').then(listing => console.log(listing))
.catch(err => console.error(err));
或者,您可以在 ES7 的异步函数中编写它们:
async function myReaddir () {
try {
const file = await fs.readdir('./myDir/');
}
catch (err) { console.error( err ) }
};
递归列表的更新
一些用户已指定希望查看递归列表(尽管不在问题中)...使用 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));
非递归版本
你没有说你想递归地做,所以我假设你只需要目录的直接子级。
示例代码:
const fs = require('fs');
const path = require('path');
fs.readdirSync('your-directory-path')
.filter((file) => fs.lstatSync(path.join(folder, file)).isFile());
依赖关系。
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
过于乐观。对于任何严重的事情,添加一些错误处理。
excludeDirs
数组参数。它改变了它,所以也许你应该编辑它(如果你想要的话)。否则,我会将其添加到不同的答案中。 gist.github.com/AlecTaylor/f3f221b4fb86b4375650
我从您的问题中假设您不需要目录名称,只需要文件。
目录结构示例
animals
├── all.jpg
├── mammals
│ └── cat.jpg
│ └── dog.jpg
└── insects
└── bee.jpg
步行功能
学分在 this gist 中转到 Justin Maier
如果您想要只是一个数组的文件路径,请使用 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), []);
}
用法
async function main() {
console.log(await walk('animals'))
}
输出
[
"/animals/all.jpg",
"/animals/mammals/cat.jpg",
"/animals/mammals/dog.jpg",
"/animals/insects/bee.jpg"
];
return
之前添加 files.unshift(dir)
。无论如何,如果您可以创建一个新问题,那将是最好的,因为它可能会帮助其他有相同需求的人并获得更好的反馈。 ;-)
animals/mammals/name
,我想通过提供一些深度来停止哺乳动物 [ "/animals/all.jpg", "/animals/mammals/cat.jpg", "/animals/mammals/dog.jpg", "/animals/insects/bee.jpg" ];
如果有人还在搜索这个,我这样做:
从'fs'导入fs;从“路径”导入路径; 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]; }, []);
它的工作对我来说非常好
[...files, ...getAllFiles(name)]
或 [...files, name]
的工作原理。一点解释会很有帮助:)
...
称为扩展语法。它基本上所做的是将数组中的所有对象“传播”到新数组中。在这种情况下,files
数组中的所有条目与递归调用返回的所有值一起添加到返回中。您可以在此处参考展开语法:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
加载 fs
:
const fs = require('fs');
异步读取文件:
fs.readdir('./dir', function (err, files) {
// "files" is an Array with files names
});
读取文件同步:
var files = fs.readdirSync('./dir');
我的一个班轮代码:
const fs = require("fs")
const path = 'somePath/'
const filesArray = fs.readdirSync(path).filter(file => fs.lstatSync(path+file).isFile())
获取 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();
}
如果有人:我的 2 美分:
只想从项目的本地子文件夹中列出文件名(不包括目录)
✅ 没有额外的依赖
✅ 1 个功能
✅ 规范化路径(Unix vs. 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) {
// ...
}
};
README.md
package.json
resources
|-- countries
|-- usa.yaml
|-- japan.yaml
|-- gb.yaml
|-- provinces
|-- .........
listFileNames("resources/countries") #=> ["usa", "japan", "gb"]
path
是您导入的 require('path')
的名称,但随后您在函数内重新定义了 const path
...这真的很混乱,可能会导致错误!
这是一个 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
}
盒子外面
如果您想要一个开箱即用的具有目录结构的对象,我强烈建议您检查 directory-tree。
假设你有这个结构:
photos
│ june
│ └── windsurf.jpg
└── january
├── ski.png
└── snowboard.jpg
const dirTree = require("directory-tree");
const tree = dirTree("/path/to/photos");
将返回:
{
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"
}
]
}
]
}
自定义对象
否则,如果您想使用自定义设置创建目录树对象,请查看以下代码段。此 codesandbox 上有一个实时示例。
// my-script.js
const fs = require("fs");
const path = require("path");
const isDirectory = filePath => fs.statSync(filePath).isDirectory();
const isFile = filePath => fs.statSync(filePath).isFile();
const getDirectoryDetails = filePath => {
const dirs = fs.readdirSync(filePath);
return {
dirs: dirs.filter(name => isDirectory(path.join(filePath, name))),
files: dirs.filter(name => isFile(path.join(filePath, name)))
};
};
const getFilesRecursively = (parentPath, currentFolder) => {
const currentFolderPath = path.join(parentPath, currentFolder);
let currentDirectoryDetails = getDirectoryDetails(currentFolderPath);
const final = {
current_dir: currentFolder,
dirs: currentDirectoryDetails.dirs.map(dir =>
getFilesRecursively(currentFolderPath, dir)
),
files: currentDirectoryDetails.files
};
return final;
};
const getAllFiles = relativePath => {
const fullPath = path.join(__dirname, relativePath);
const parentDirectoryPath = path.dirname(fullPath);
const leafDirectory = path.basename(fullPath);
const allFiles = getFilesRecursively(parentDirectoryPath, leafDirectory);
return allFiles;
};
module.exports = { getAllFiles };
然后你可以简单地做:
// another-file.js
const { getAllFiles } = require("path/to/my-script");
const allFiles = getAllFiles("/path/to/my-directory");
这是一个异步递归版本。
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()
}
采用@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]);
}, []);
}
示例用法:
console.log(fileList('.', ['node_modules', 'typings', 'bower_components']));
它只有两行代码:
fs=require('fs')
fs.readdir("./img/", (err,filename)=>console.log(filename))
https://i.stack.imgur.com/TlQME.png
使用 flatMap:
function getFiles(dir) {
return fs.readdirSync(dir).flatMap((item) => {
const path = `${dir}/${item}`;
if (fs.statSync(path).isDirectory()) {
return getFiles(path);
}
return path;
});
}
给定以下目录:
dist
├── 404.html
├── app-AHOLRMYQ.js
├── img
│ ├── demo.gif
│ └── start.png
├── index.html
└── sw.js
用法:
getFiles("dist")
输出:
[
'dist/404.html',
'dist/app-AHOLRMYQ.js',
'dist/img/demo.gif',
'dist/img/start.png',
'dist/index.html'
]
我通常使用:FS-Extra。
const fileNameArray = Fse.readdir('/some/path');
结果:
[
"b7c8a93c-45b3-4de8-b9b5-a0bf28fb986e.jpg",
"daeb1c5b-809f-4434-8fd9-410140789933.jpg"
]
这将起作用并将结果存储在 test.txt 文件中,该文件将出现在同一目录中
fs.readdirSync(__dirname).forEach(file => {
fs.appendFileSync("test.txt", file+"\n", function(err){
})
})
我最近为此构建了一个工具来执行此操作...它异步获取目录并返回项目列表。您可以获取目录、文件或两者,首先是文件夹。如果您不想获取整个文件夹,也可以对数据进行分页。
https://www.npmjs.com/package/fs-browser
这是链接,希望对某人有所帮助!
我制作了一个节点模块来自动执行此任务:mddir
用法
节点 mddir "../relative/path/"
安装: npm install mddir -g
为当前目录生成markdown:mddir
为任何绝对路径生成: mddir /absolute/path
为相对路径生成:mddir ~/Documents/whatever。
md 文件在您的工作目录中生成。
当前忽略 node_modules 和 .git 文件夹。
故障排除
如果您收到错误“节点\r:没有此类文件或目录”,则问题是您的操作系统使用不同的行尾,并且 mddir 无法解析它们,除非您将行尾样式显式设置为 Unix。这通常会影响 Windows,但也会影响某些版本的 Linux。必须在 mddir npm 全局 bin 文件夹中将行尾设置为 Unix 样式。
行尾修复
获取 npm bin 文件夹路径:
npm config get prefix
cd到那个文件夹
冲泡安装dos2unix
dos2unix lib/node_modules/mddir/src/mddir.js
这会将行尾转换为 Unix 而不是 Dos
然后正常运行:node mddir "../relative/path/"。
示例生成的降价文件结构 '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
使用 npm
list-contents 模块。它读取给定目录的内容和子内容,并返回文件和文件夹路径的列表。
const list = require('list-contents');
list("./dist",(o)=>{
if(o.error) throw o.error;
console.log('Folders: ', o.dirs);
console.log('Files: ', o.files);
});
如果上述许多选项看起来太复杂或不是您正在寻找的,这里是另一种使用 node-dir 的方法 - https://github.com/fshost/node-dir
npm install node-dir
这是一个列出在子目录中搜索的所有 .xml 文件的简单函数
import * as nDir from 'node-dir' ;
listXMLs(rootFolderPath) {
let xmlFiles ;
nDir.files(rootFolderPath, function(err, items) {
xmlFiles = items.filter(i => {
return path.extname(i) === '.xml' ;
}) ;
console.log(xmlFiles) ;
});
}
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);
}
}
}
readdir
还显示目录名称。要过滤这些,请使用fs.stat(path, callback(err, stats))
和stats.isDirectory()
。ls
的输出吗?等到有人创建一些带有嵌入空格和换行符的文件名......