获取nodejs目录下的所有目录

我希望这是一件简单的事情,但我找不到任何东西在那里这样做。

我只想获得给定文件夹/目录内的所有文件夹/目录。

例如:

<MyFolder>
|- SomeFolder
|- SomeOtherFolder
|- SomeFile.txt
|- SomeOtherFile.txt
|- x-directory

我期望得到一个数组:

["SomeFolder", "SomeOtherFolder", "x-directory"]

或者上面的路径,如果它是这样提供的……

那么,有什么东西已经存在了吗?

264241 次浏览

这应该做到:

CoffeeScript(同步)

fs = require 'fs'


getDirs = (rootDir) ->
files = fs.readdirSync(rootDir)
dirs = []


for file in files
if file[0] != '.'
filePath = "#{rootDir}/#{file}"
stat = fs.statSync(filePath)


if stat.isDirectory()
dirs.push(file)


return dirs

CoffeeScript(异步)

fs = require 'fs'


getDirs = (rootDir, cb) ->
fs.readdir rootDir, (err, files) ->
dirs = []


for file, index in files
if file[0] != '.'
filePath = "#{rootDir}/#{file}"
fs.stat filePath, (err, stat) ->
if stat.isDirectory()
dirs.push(file)
if files.length == (index + 1)
cb(dirs)

JavaScript(异步)

var fs = require('fs');
var getDirs = function(rootDir, cb) {
fs.readdir(rootDir, function(err, files) {
var dirs = [];
for (var index = 0; index < files.length; ++index) {
var file = files[index];
if (file[0] !== '.') {
var filePath = rootDir + '/' + file;
fs.stat(filePath, function(err, stat) {
if (stat.isDirectory()) {
dirs.push(this.file);
}
if (files.length === (this.index + 1)) {
return cb(dirs);
}
}.bind({index: index, file: file}));
}
}
});
}

承诺

import { readdir } from 'fs/promises'


const getDirectories = async source =>
(await readdir(source, { withFileTypes: true }))
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)

回调

import { readdir } from 'fs'


const getDirectories = (source, callback) =>
readdir(source, { withFileTypes: true }, (err, files) => {
if (err) {
callback(err)
} else {
callback(
files
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)
)
}
})

Syncronous

import { readdirSync } from 'fs'


const getDirectories = source =>
readdirSync(source, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name)

使用路径列出目录。

function getDirectories(path) {
return fs.readdirSync(path).filter(function (file) {
return fs.statSync(path+'/'+file).isDirectory();
});
}

对于getDirectories的异步版本,你需要异步模块来实现:

var fs = require('fs');
var path = require('path');
var async = require('async'); // https://github.com/caolan/async


// Original function
function getDirsSync(srcpath) {
return fs.readdirSync(srcpath).filter(function(file) {
return fs.statSync(path.join(srcpath, file)).isDirectory();
});
}


function getDirs(srcpath, cb) {
fs.readdir(srcpath, function (err, files) {
if(err) {
console.error(err);
return cb([]);
}
var iterator = function (file, cb)  {
fs.stat(path.join(srcpath, file), function (err, stats) {
if(err) {
console.error(err);
return cb(false);
}
cb(stats.isDirectory());
})
}
async.filter(files, iterator, cb);
});
}

这个答案的CoffeeScript版本,具有适当的错误处理:

fs = require "fs"
{join} = require "path"
async = require "async"


get_subdirs = (root, callback)->
fs.readdir root, (err, files)->
return callback err if err
subdirs = []
async.each files,
(file, callback)->
fs.stat join(root, file), (err, stats)->
return callback err if err
subdirs.push file if stats.isDirectory()
callback null
(err)->
return callback err if err
callback null, subdirs

取决于异步

或者,使用一个模块! (所有东西都有模块。[引文需要])< / p >

以防其他人从网络搜索到这里,并且已经在他们的依赖列表中有Grunt,这个问题的答案变得微不足道。以下是我的解决方案:

/**
* Return all the subfolders of this path
* @param {String} parentFolderPath - valid folder path
* @param {String} glob ['/*'] - optional glob so you can do recursive if you want
* @returns {String[]} subfolder paths
*/
getSubfolders = (parentFolderPath, glob = '/*') => {
return grunt.file.expand({filter: 'isDirectory'}, parentFolderPath + glob);
}

递归解决方案

我来这里是为了寻找一种方法来获取所有子目录,以及它们的所有子目录,等等。在接受的答案的基础上,我写了这个:

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


function flatten(lists) {
return lists.reduce((a, b) => a.concat(b), []);
}


function getDirectories(srcpath) {
return fs.readdirSync(srcpath)
.map(file => path.join(srcpath, file))
.filter(path => fs.statSync(path).isDirectory());
}


function getDirectoriesRecursive(srcpath) {
return [srcpath, ...flatten(getDirectories(srcpath).map(getDirectoriesRecursive))];
}

或者,如果你能够使用外部库,你可以使用filehound。它支持回调,承诺和同步调用。

使用承诺:

const Filehound = require('filehound');


Filehound.create()
.path("MyFolder")
.directory() // only search for directories
.find()
.then((subdirectories) => {
console.log(subdirectories);
});

使用回调函数:

const Filehound = require('filehound');


Filehound.create()
.path("MyFolder")
.directory()
.find((err, subdirectories) => {
if (err) return console.error(err);


console.log(subdirectories);
});

同步调用:

const Filehound = require('filehound');


const subdirectories = Filehound.create()
.path("MyFolder")
.directory()
.findSync();


console.log(subdirectories);

有关更多信息(和示例),请查看文档:https://github.com/nspragg/filehound

声明:我是作者。

如果需要使用全部async版本。你可以有这样的东西。

  1. 记录目录长度,使用它作为一个指示器,以告知是否所有异步统计任务已完成。

  2. 如果异步统计任务已完成,则所有文件统计都已检查,因此调用回调

这将只在Node.js是单线程的情况下工作,因为它假设没有两个异步任务会同时增加计数器。

'use strict';


var fs = require("fs");
var path = require("path");
var basePath = "./";


function result_callback(results) {
results.forEach((obj) => {
console.log("isFile: " + obj.fileName);
console.log("fileName: " + obj.isFile);
});
};


fs.readdir(basePath, (err, files) => {
var results = [];
var total = files.length;
var finished = 0;


files.forEach((fileName) => {
// console.log(fileName);
var fullPath = path.join(basePath, fileName);


fs.stat(fullPath, (err, stat) => {
// this will work because Node.js is single thread
// therefore, the counter will not increment at the same time by two callback
finished++;


if (stat.isFile()) {
results.push({
fileName: fileName,
isFile: stat.isFile()
});
}


if (finished == total) {
result_callback(results);
}
});
});
});

正如您所看到的,这是一种“深度优先”的方法,这可能会导致回调地狱,而且它不是完全“功能性的”。人们试图用Promise来解决这个问题,方法是将异步任务包装到Promise对象中。

'use strict';


var fs = require("fs");
var path = require("path");
var basePath = "./";


function result_callback(results) {
results.forEach((obj) => {
console.log("isFile: " + obj.fileName);
console.log("fileName: " + obj.isFile);
});
};


fs.readdir(basePath, (err, files) => {
var results = [];
var total = files.length;
var finished = 0;


var promises = files.map((fileName) => {
// console.log(fileName);
var fullPath = path.join(basePath, fileName);


return new Promise((resolve, reject) => {
// try to replace fullPath wil "aaa", it will reject
fs.stat(fullPath, (err, stat) => {
if (err) {
reject(err);
return;
}


var obj = {
fileName: fileName,
isFile: stat.isFile()
};


resolve(obj);
});
});
});


Promise.all(promises).then((values) => {
console.log("All the promise resolved");
console.log(values);
console.log("Filter out folder: ");
values
.filter((obj) => obj.isFile)
.forEach((obj) => {
console.log(obj.fileName);
});
}, (reason) => {
console.log("Not all the promise resolved");
console.log(reason);
});
});

使用fs, path模块可以获取文件夹。这使用承诺。如果你想要填充,你可以将isDirectory ()改为isFile () Nodejs - fs - fs。统计数据。最后,你可以得到文件'name file'extname等等Nodejs——路径

var fs = require("fs"),
path = require("path");
//your <MyFolder> path
var p = "MyFolder"
fs.readdir(p, function (err, files) {
if (err) {
throw err;
}
//this can get all folder and file under  <MyFolder>
files.map(function (file) {
//return file or folder path, such as **MyFolder/SomeFile.txt**
return path.join(p, file);
}).filter(function (file) {
//use sync judge method. The file will add next files array if the file is directory, or not.
return fs.statSync(file).isDirectory();
}).forEach(function (files) {
//The files is array, so each. files is the folder name. can handle the folder.
console.log("%s", files);
});
});

使用fs-extra,承诺async fs调用,以及新的await async语法:

const fs = require("fs-extra");


async function getDirectories(path){
let filesAndDirectories = await fs.readdir(path);


let directories = [];
await Promise.all(
filesAndDirectories.map(name =>{
return fs.stat(path + name)
.then(stat =>{
if(stat.isDirectory()) directories.push(name)
})
})
);
return directories;
}


let directories = await getDirectories("/")

对于node.js版本>= v10.13.0,如果withFileTypes选项被设置为truefs.readdirSync将返回一个fs。Dirent对象数组。

所以你可以用,

const fs = require('fs')


const directories = source => fs.readdirSync(source, {
withFileTypes: true
}).reduce((a, c) => {
c.isDirectory() && a.push(c.name)
return a
}, [])

另一种递归方法

感谢Mayur了解我的withFileTypes。我写了下面的代码来递归地获取特定文件夹的文件。可以很容易地修改它以只获取目录。

const getFiles = (dir, base = '') => readdirSync(dir, {withFileTypes: true}).reduce((files, file) => {
const filePath = path.join(dir, file.name)
const relativePath = path.join(base, file.name)
if(file.isDirectory()) {
return files.concat(getFiles(filePath, relativePath))
} else if(file.isFile()) {
file.__fullPath = filePath
file.__relateivePath = relativePath
return files.concat(file)
}
}, [])

函数式编程

const fs = require('fs')
const path = require('path')
const R = require('ramda')


const getDirectories = pathName => {
const isDirectory = pathName => fs.lstatSync(pathName).isDirectory()
const mapDirectories = pathName => R.map(name => path.join(pathName, name), fs.readdirSync(pathName))
const filterDirectories = listPaths => R.filter(isDirectory, listPaths)


return {
paths:R.pipe(mapDirectories)(pathName),
pathsFiltered: R.pipe(mapDirectories, filterDirectories)(pathName)
}
}

这个答案不使用像readdirSyncstatSync这样的阻塞函数。它不使用外部依赖关系,也不陷入回调地狱的深渊。

相反,我们使用现代JavaScript的便利,如Promises和async-await语法。异步结果是并行处理的;〇不是按顺序

const { readdir, stat } =
require ("fs") .promises


const { join } =
require ("path")


const dirs = async (path = ".") =>
(await stat (path)) .isDirectory ()
? Promise
.all
( (await readdir (path))
.map (p => dirs (join (path, p)))
)
.then
( results =>
[] .concat (path, ...results)
)
: []

我将安装一个示例包,然后测试我们的函数-

$ npm install ramda
$ node

让我们看看它是如何工作的

> dirs (".") .then (console.log, console.error)


[ '.'
, 'node_modules'
, 'node_modules/ramda'
, 'node_modules/ramda/dist'
, 'node_modules/ramda/es'
, 'node_modules/ramda/es/internal'
, 'node_modules/ramda/src'
, 'node_modules/ramda/src/internal'
]

使用泛化模块Parallel,我们可以简化dirs -的定义

const Parallel =
require ("./Parallel")


const dirs = async (path = ".") =>
(await stat (path)) .isDirectory ()
? Parallel (readdir (path))
.flatMap (f => dirs (join (path, f)))
.then (results => [ path, ...results ])
: []

上面使用的Parallel模块是从一组旨在解决类似问题的函数中提取出来的模式。有关更多解释,请参见相关Q&

 var getDirectories = (rootdir , cb) => {
fs.readdir(rootdir, (err, files) => {
if(err) throw err ;
var dirs = files.map(filename => path.join(rootdir,filename)).filter( pathname => fs.statSync(pathname).isDirectory());
return cb(dirs);
})


}
getDirectories( myDirectories => console.log(myDirectories));``

完全异步的版本与ES6,只有本机包,fs。Promises和async/await,并行执行文件操作:

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


async function listDirectories(rootPath) {
const fileNames = await fs.promises.readdir(rootPath);
const filePaths = fileNames.map(fileName => path.join(rootPath, fileName));
const filePathsAndIsDirectoryFlagsPromises = filePaths.map(async filePath => ({path: filePath, isDirectory: (await fs.promises.stat(filePath)).isDirectory()}))
const filePathsAndIsDirectoryFlags = await Promise.all(filePathsAndIsDirectoryFlagsPromises);
return filePathsAndIsDirectoryFlags.filter(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.isDirectory)
.map(filePathAndIsDirectoryFlag => filePathAndIsDirectoryFlag.path);
}

经过测试,它工作得很好。

你可以使用graph-fs

const {Node} = require("graph-fs");
const directory = new Node("/path/to/directory");


const subDirectories = directory.children.filter(child => child.is.directory);

你可以使用使人意志消沉的,如果使用一个模块是负担得起的

const dree = require('dree');


const options = {
depth: 1
};
const fileCallback = function() {};


const directories = [];
const dirCallback = function(dir) {
directories.push(dir.name);
};


dree.scan('./dir', {});


console.log(directories);

指定路径("./dir")的子目录将被打印。

如果你不设置选项depth: 1,你甚至会以递归的方式获取所有目录,而不仅仅是指定路径的有向子目录。

使用一团包,只需要添加一个斜杠来查找目录:

import {promise as glob} from "glob-promise"


const firstLevelFolders = await glob("MyFolder/*/")
const recursiveFolders = await glob("MyFolder/**/")