在Javascript中获取文件夹和文件列表的最佳方法
我正在使用node webkit,并试图让用户选择一个文件夹,我将返回该文件夹的目录结构并递归地获取其子文件夹 我用这段代码(在一个角度控制器中)就可以很简单地实现这一点 以一个中等大小的文件夹为例,它有22个子文件夹,深度约为4层,需要几分钟才能获得整个目录结构 这里有什么我明显做错的吗?我不敢相信这会花那么长时间,因为我正在使用内置的节点fs方法。或者有没有一种方法可以在不接触每个文件的情况下获取目录的全部内容在Javascript中获取文件夹和文件列表的最佳方法,javascript,node.js,recursion,filesystems,Javascript,Node.js,Recursion,Filesystems,我正在使用node webkit,并试图让用户选择一个文件夹,我将返回该文件夹的目录结构并递归地获取其子文件夹 我用这段代码(在一个角度控制器中)就可以很简单地实现这一点 以一个中等大小的文件夹为例,它有22个子文件夹,深度约为4层,需要几分钟才能获得整个目录结构 这里有什么我明显做错的吗?我不敢相信这会花那么长时间,因为我正在使用内置的节点fs方法。或者有没有一种方法可以在不接触每个文件的情况下获取目录的全部内容 我希望能够在整个树的文件名上使用角度过滤器,也可能在内容上使用角度过滤器,因此延
我希望能够在整个树的文件名上使用角度过滤器,也可能在内容上使用角度过滤器,因此延迟处理整个树不太可能是一个可行的解决方案 在我的项目中,我使用此功能获取大量文件。它非常快(将
require(“FS”)
输出以使其更快):
用法很清楚:
_getAllFilesFromFolder(__dirname + "folder");
为什么要发明轮子 有一个非常流行的NPM软件包,它可以让你轻松地完成类似的事情
var recursive = require("recursive-readdir");
recursive("some/path", function (err, files) {
// `files` is an array of file paths
console.log(files);
});
了解更多:
- 我不喜欢仅仅为了处理这个简单的任务而在我的项目中添加新的包
而且,我尽量避免使用递归算法。。。。因为,在大多数情况下,它比非递归的慢
所以我做了一个函数来获取所有文件夹内容(及其子文件夹)。。。。非递归
var getDirectoryContent = function(dirPath) {
/*
get list of files and directories from given dirPath and all it's sub directories
NON RECURSIVE ALGORITHM
By. Dreamsavior
*/
var RESULT = {'files':[], 'dirs':[]};
var fs = fs||require('fs');
if (Boolean(dirPath) == false) {
return RESULT;
}
if (fs.existsSync(dirPath) == false) {
console.warn("Path does not exist : ", dirPath);
return RESULT;
}
var directoryList = []
var DIRECTORY_SEPARATOR = "\\";
if (dirPath[dirPath.length -1] !== DIRECTORY_SEPARATOR) dirPath = dirPath+DIRECTORY_SEPARATOR;
directoryList.push(dirPath); // initial
while (directoryList.length > 0) {
var thisDir = directoryList.shift();
if (Boolean(fs.existsSync(thisDir) && fs.lstatSync(thisDir).isDirectory()) == false) continue;
var thisDirContent = fs.readdirSync(thisDir);
while (thisDirContent.length > 0) {
var thisFile = thisDirContent.shift();
var objPath = thisDir+thisFile
if (fs.existsSync(objPath) == false) continue;
if (fs.lstatSync(objPath).isDirectory()) { // is a directory
let thisDirPath = objPath+DIRECTORY_SEPARATOR;
directoryList.push(thisDirPath);
RESULT['dirs'].push(thisDirPath);
} else { // is a file
RESULT['files'].push(objPath);
}
}
}
return RESULT;
}
此函数的唯一缺点是它是同步函数。。。您已被警告;) fs/promises和fs.Dirent 这是一个高效、无阻塞的
ls
程序,使用节点的快速对象和模块。这种方法允许您跳过每个路径上浪费的fs.exist
或fs.stat
调用-
// main.js
import { readdir } from "fs/promises"
import { join } from "path"
async function* ls (path = ".")
{ yield path
for (const dirent of await readdir(path, { withFileTypes: true }))
if (dirent.isDirectory())
yield* ls(join(path, dirent.name))
else
yield join(path, dirent.name)
}
async function* empty () {}
async function toArray (iter = empty())
{ let r = []
for await (const x of iter)
r.push(x)
return r
}
toArray(ls(".")).then(console.log, console.error)
让我们获取一些示例文件,这样我们就可以看到ls
正在工作-
$warn add immutable#(只是一些示例包)
$node main.js
[
'.',
'main.js',
“节点_模块”,
“节点\单元/纱线完整性”,
“节点_模块/不可变”,
“节点\模块/不可变/许可证”,
“node_modules/immutable/README.md”,
“节点\模块/不可变/可控”,
“节点\模块/不可变/控制/游标”,
'node_modules/immutable/contrib/cursor/README.md',
'节点\模块/不可变/contrib/cursor/\测试\',
'节点\模块/immutable/contrib/cursor/\测试\测试\ cursor.ts.skip',
“node_modules/immutable/contrib/cursor/index.d.ts”,
'node_modules/immutable/contrib/cursor/index.js',
“节点\模块/不可变/dist”,
'node_modules/immutable/dist/immutable nonambient.d.ts',
'node_modules/immutable/dist/immutable.d.ts',
'node_modules/immutable/dist/immutable.es.js',
'node_modules/immutable/dist/immutable.js',
'node_modules/immutable/dist/immutable.js.flow',
'node_modules/immutable/dist/immutable.min.js',
“node_modules/immutable/package.json”,
'package.json',
“纱线,锁”
]
有关利用异步生成器的更多说明和其他方法,请参阅。也许它是。。作为一个文件。您可能应该放置一些控制台。日志的周围,以了解更多关于正在发生的事情。您的意思是它正在打开每个文件?不,这似乎不是问题所在,我正要删除这个问题,结果是,如果我删除了console.log并放入一个回调,该回调输出到控制台一次,事情就会发生得更快。我的意思是..,父目录,但这是一个很长的问题。很好,您找到了解决方案,但您需要的是一个简单的遍历目录的递归遍历函数。谷歌是你的朋友。有没有一种非递归的方法可以做到这一点?没有定义“require”函数。@Jacob在tags@GeekyInt您的目录结构中可能有一个指向包含文件夹的符号链接。在这种情况下,您可以使用
fs.lstat()
而不是fs.stat()
。为了使用节点的fastfs.Dirent
对象实现高效的非阻塞(异步)技术,我将其添加到此线程中。此解决方案本身不列出目录
var getDirectoryContent = function(dirPath) {
/*
get list of files and directories from given dirPath and all it's sub directories
NON RECURSIVE ALGORITHM
By. Dreamsavior
*/
var RESULT = {'files':[], 'dirs':[]};
var fs = fs||require('fs');
if (Boolean(dirPath) == false) {
return RESULT;
}
if (fs.existsSync(dirPath) == false) {
console.warn("Path does not exist : ", dirPath);
return RESULT;
}
var directoryList = []
var DIRECTORY_SEPARATOR = "\\";
if (dirPath[dirPath.length -1] !== DIRECTORY_SEPARATOR) dirPath = dirPath+DIRECTORY_SEPARATOR;
directoryList.push(dirPath); // initial
while (directoryList.length > 0) {
var thisDir = directoryList.shift();
if (Boolean(fs.existsSync(thisDir) && fs.lstatSync(thisDir).isDirectory()) == false) continue;
var thisDirContent = fs.readdirSync(thisDir);
while (thisDirContent.length > 0) {
var thisFile = thisDirContent.shift();
var objPath = thisDir+thisFile
if (fs.existsSync(objPath) == false) continue;
if (fs.lstatSync(objPath).isDirectory()) { // is a directory
let thisDirPath = objPath+DIRECTORY_SEPARATOR;
directoryList.push(thisDirPath);
RESULT['dirs'].push(thisDirPath);
} else { // is a file
RESULT['files'].push(objPath);
}
}
}
return RESULT;
}
// main.js
import { readdir } from "fs/promises"
import { join } from "path"
async function* ls (path = ".")
{ yield path
for (const dirent of await readdir(path, { withFileTypes: true }))
if (dirent.isDirectory())
yield* ls(join(path, dirent.name))
else
yield join(path, dirent.name)
}
async function* empty () {}
async function toArray (iter = empty())
{ let r = []
for await (const x of iter)
r.push(x)
return r
}
toArray(ls(".")).then(console.log, console.error)