使用fs.readdir进行异步目录搜索的任何想法?我意识到我们可以引入递归并调用读取目录函数与下一个目录来读取,但有点担心它不是异步...
有什么想法吗?我看了node-walk这很好,但是不给我一个数组中的文件,比如readdir。虽然
寻找类似......
的输出['file1.txt', 'file2.txt', 'dir/file3.txt']
答案 0 :(得分:354)
基本上有两种方法可以实现这一点。在异步环境中,您会注意到有两种循环:串行和并行。串行循环在进入下一次迭代之前等待一次迭代完成 - 这保证循环的每次迭代按顺序完成。在并行循环中,所有迭代都是同时启动的,并且可以在另一个迭代之前完成,但是,它比串行循环快得多。因此,在这种情况下,使用并行循环可能更好,因为步行完成的顺序无关紧要,只要它完成并返回结果(除非您按顺序要求它们)。
并行循环看起来像这样:
var fs = require('fs');
var path = require('path');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var pending = list.length;
if (!pending) return done(null, results);
list.forEach(function(file) {
file = path.resolve(dir, file);
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
if (!--pending) done(null, results);
});
} else {
results.push(file);
if (!--pending) done(null, results);
}
});
});
});
};
串行循环如下所示:
var fs = require('fs');
var walk = function(dir, done) {
var results = [];
fs.readdir(dir, function(err, list) {
if (err) return done(err);
var i = 0;
(function next() {
var file = list[i++];
if (!file) return done(null, results);
file = dir + '/' + file;
fs.stat(file, function(err, stat) {
if (stat && stat.isDirectory()) {
walk(file, function(err, res) {
results = results.concat(res);
next();
});
} else {
results.push(file);
next();
}
});
})();
});
};
并在您的主目录中测试它(警告:如果您的主目录中有很多东西,结果列表将会很大):
walk(process.env.HOME, function(err, results) {
if (err) throw err;
console.log(results);
});
编辑:改进的例子。
答案 1 :(得分:89)
如果有人发现它有用,我还会整理一个同步版本。
var walk = function(dir) {
var results = [];
var list = fs.readdirSync(dir);
list.forEach(function(file) {
file = dir + '/' + file;
var stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
/* Recurse into a subdirectory */
results = results.concat(walk(file));
} else {
/* Is a file */
results.push(file);
}
});
return results;
}
提示:过滤时使用较少的资源。在此功能本身内过滤。例如。用以下代码替换results.push(file);
。根据需要进行调整:
file_type = file.split(".").pop();
file_name = file.split(/(\\|\/)/g).pop();
if (file_type == "json") results.push(file);
答案 2 :(得分:83)
A。查看file module。它有一个叫做walk的函数:
file.walk(开始,回调)
导航文件树,为每个目录调用回调,传入 (null,dirPath,dirs,files)。
这可能适合你!是的,它是异步的。但是,如果您需要,我认为您必须自己聚合完整路径。
B。另一种选择,甚至是我的最爱之一:使用unix find
。为什么要再做一次,已经编程了?也许不完全是你需要的,但仍然值得一试:
var execFile = require('child_process').execFile;
execFile('find', [ 'somepath/' ], function(err, stdout, stderr) {
var file_list = stdout.split('\n');
/* now you've got a list with full path file names */
});
Find有一个很好的内置缓存机制,只要只有少数文件夹发生变化,后续搜索速度非常快。
答案 3 :(得分:66)
这个使用节点8中可用的最新的buzzwordy功能,包括Promises,util / promisify,destructuring,async-await,map + reduce等等,让你的同事们试图抓住他们的头脑。弄清楚发生了什么。
没有外部依赖。
const { promisify } = require('util');
const { resolve } = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
async function getFiles(dir) {
const subdirs = await readdir(dir);
const files = await Promise.all(subdirs.map(async (subdir) => {
const res = resolve(dir, subdir);
return (await stat(res)).isDirectory() ? getFiles(res) : res;
}));
return files.reduce((a, f) => a.concat(f), []);
}
用法:
getFiles(__dirname)
.then(files => console.log(files))
.catch(e => console.error(e));
为节点10+更新了更多的whizbang:
const { resolve } = require('path');
const { readdir, stat } = require('fs').promises;
async function getFiles(dir) {
const subdirs = await readdir(dir);
const files = await Promise.all(subdirs.map(async (subdir) => {
const res = resolve(dir, subdir);
return (await stat(res)).isDirectory() ? getFiles(res) : res;
}));
return Array.prototype.concat(...files);
}
如果你想让每个人都完全放心,你可以使用 async iterators 来使用以下版本。除了非常酷,它还允许消费者一次一个地提取结果,使其更适合真正的大型目录。
const { resolve } = require('path');
const { readdir, stat } = require('fs').promises;
async function* getFiles(dir) {
const subdirs = await readdir(dir);
for (const subdir of subdirs) {
const res = resolve(dir, subdir);
if ((await stat(res)).isDirectory()) {
yield* getFiles(res);
} else {
yield res;
}
}
}
用法已更改,因为返回类型现在是异步迭代器而不是promise
(async () => {
for await (const f of getFiles('.')) {
console.log(f);
}
})()
如果有人感兴趣,我在这里写了更多关于异步迭代器的文章:https://qwtel.com/posts/software/async-generators-in-the-wild/
答案 4 :(得分:37)
另一个不错的npm包是glob。
npm install glob
它非常强大,应该涵盖您所有的递归需求。
我实际上对glob不是很满意,所以我创建了readdirp。
我非常有信心它的API可以递归地查找文件和目录,并且非常容易应用特定的过滤器。
仔细阅读documentation以更好地了解它的作用并通过以下方式安装:
npm install readdirp
答案 5 :(得分:26)
我建议使用node-glob来完成该任务。
var glob = require( 'glob' );
glob( 'dirname/**/*.js', function( err, files ) {
console.log( files );
});
答案 6 :(得分:15)
如果你想使用npm包,wrench非常好。
var wrench = require("wrench");
var files = wrench.readdirSyncRecursive("directory");
wrench.readdirRecursive("directory", function (error, files) {
// live your dreams
});
编辑(2018):
最近阅读的人:作者在2015年弃用了这个软件包:
wrench.js已弃用,并且在相当长的一段时间内尚未更新。 I heavily recommend using fs-extra进行任何额外的文件系统操作。
答案 7 :(得分:9)
我喜欢上面the answer的chjj,如果没有开始,就无法创建我的并行循环版本。
var fs = require("fs");
var tree = function(dir, done) {
var results = {
"path": dir
,"children": []
};
fs.readdir(dir, function(err, list) {
if (err) { return done(err); }
var pending = list.length;
if (!pending) { return done(null, results); }
list.forEach(function(file) {
fs.stat(dir + '/' + file, function(err, stat) {
if (stat && stat.isDirectory()) {
tree(dir + '/' + file, function(err, res) {
results.children.push(res);
if (!--pending){ done(null, results); }
});
} else {
results.children.push({"path": dir + "/" + file});
if (!--pending) { done(null, results); }
}
});
});
});
};
module.exports = tree;
我也创建了a Gist。欢迎评论。我仍然在NodeJS领域开始,所以这是我希望了解更多的一种方式。
答案 8 :(得分:8)
使用node-dir准确生成您喜欢的输出
var dir = require('node-dir');
dir.files(__dirname, function(err, files) {
if (err) throw err;
console.log(files);
//we have an array of files now, so now we can iterate that array
files.forEach(function(path) {
action(null, path);
})
});
答案 9 :(得分:7)
使用递归
var fs = require('fs')
var path = process.cwd()
var files = []
var getFiles = function(path, files){
fs.readdirSync(path).forEach(function(file){
var subpath = path + '/' + file;
if(fs.lstatSync(subpath).isDirectory()){
getFiles(subpath, files);
} else {
files.push(path + '/' + file);
}
});
}
调用
getFiles(path, files)
console.log(files) // will log all files in directory
答案 10 :(得分:4)
我最近对此进行了编码,并认为在此处分享这一点是有意义的。该代码使用async library。
var fs = require('fs');
var async = require('async');
var scan = function(dir, suffix, callback) {
fs.readdir(dir, function(err, files) {
var returnFiles = [];
async.each(files, function(file, next) {
var filePath = dir + '/' + file;
fs.stat(filePath, function(err, stat) {
if (err) {
return next(err);
}
if (stat.isDirectory()) {
scan(filePath, suffix, function(err, results) {
if (err) {
return next(err);
}
returnFiles = returnFiles.concat(results);
next();
})
}
else if (stat.isFile()) {
if (file.indexOf(suffix, file.length - suffix.length) !== -1) {
returnFiles.push(filePath);
}
next();
}
});
}, function(err) {
callback(err, returnFiles);
});
});
};
你可以像这样使用它:
scan('/some/dir', '.ext', function(err, files) {
// Do something with files that ends in '.ext'.
console.log(files);
});
答案 11 :(得分:4)
使用async / await,这应该有效:
const FS = require('fs');
const readDir = promisify(FS.readdir);
const fileStat = promisify(FS.stat);
async function getFiles(dir) {
let files = await readDir(dir);
let result = files.map(file => {
let path = Path.join(dir,file);
return fileStat(path).then(stat => stat.isDirectory() ? getFiles(path) : path);
});
return flatten(await Promise.all(result));
}
function flatten(arr) {
return Array.prototype.concat(...arr);
}
您可以使用bluebird.Promisify或者:
/**
* Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
*
* @param {Function} nodeFunction
* @returns {Function}
*/
module.exports = function promisify(nodeFunction) {
return function(...args) {
return new Promise((resolve, reject) => {
nodeFunction.call(this, ...args, (err, data) => {
if(err) {
reject(err);
} else {
resolve(data);
}
})
});
};
};
节点8+有Promisify built-in
请参阅我的other answer了解可以更快地提供结果的生成器方法。
答案 12 :(得分:3)
查看final-fs库。它提供readdirRecursive
函数:
ffs.readdirRecursive(dirPath, true, 'my/initial/path')
.then(function (files) {
// in the `files` variable you've got all the files
})
.otherwise(function (err) {
// something went wrong
});
答案 13 :(得分:3)
名为 Filehound 的库是另一种选择。它将以递归方式搜索给定目录(默认情况下为工作目录)。它支持各种过滤器,回调,承诺和同步搜索。
例如,在当前工作目录中搜索所有文件(使用回调):
const Filehound = require('filehound');
Filehound.create()
.find((err, files) => {
if (err) {
return console.error(`error: ${err}`);
}
console.log(files); // array of files
});
或承诺并指定特定目录:
const Filehound = require('filehound');
Filehound.create()
.paths("/tmp")
.find()
.each(console.log);
有关更多用例和使用示例,请参阅文档:https://github.com/nspragg/filehound
免责声明:我是作者。
答案 14 :(得分:3)
qwtel 的 answer 变体,在 TypeScript
中import { resolve } from 'path';
import { readdir } from 'fs/promises';
async function* getFiles(dir: string): AsyncGenerator<string> {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const res = resolve(dir, entry.name);
if (entry.isDirectory()) {
yield* getFiles(res);
} else {
yield res;
}
}
}
答案 15 :(得分:2)
答案 16 :(得分:2)
我在这个例子中使用when.js promise库。
var fs = require('fs')
, path = require('path')
, when = require('when')
, nodefn = require('when/node/function');
function walk (directory, includeDir) {
var results = [];
return when.map(nodefn.call(fs.readdir, directory), function(file) {
file = path.join(directory, file);
return nodefn.call(fs.stat, file).then(function(stat) {
if (stat.isFile()) { return results.push(file); }
if (includeDir) { results.push(file + path.sep); }
return walk(file, includeDir).then(function(filesInDir) {
results = results.concat(filesInDir);
});
});
}).then(function() {
return results;
});
};
walk(__dirname).then(function(files) {
console.log(files);
}).otherwise(function(error) {
console.error(error.stack || error);
});
我添加了一个可选参数includeDir
,如果设置为true
,它将包含文件列表中的目录。
答案 17 :(得分:1)
想要同步替代已接受答案的人(我知道我已经做到了):
var fs = require('fs');
var path = require('path');
var walk = function(dir) {
let results = [], err = null, list;
try {
list = fs.readdirSync(dir)
} catch(e) {
err = e.toString();
}
if (err) return err;
var i = 0;
return (function next() {
var file = list[i++];
if(!file) return results;
file = path.resolve(dir, file);
let stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
let res = walk(file);
results = results.concat(res);
return next();
} else {
results.push(file);
return next();
}
})();
};
console.log(
walk("./")
)
答案 18 :(得分:1)
const fs = require('fs/promises');
const getDirRecursive = async (dir) => {
try {
const items = await fs.readdir(dir);
let files = [];
for (const item of items) {
if ((await fs.lstat(`${dir}/${item}`)).isDirectory()) files = [...files, ...(await getDirRecursive(`${dir}/${item}`))];
else files.push({file: item, path: `${dir}/${item}`, parents: dir.split("/")});
}
return files;
} catch (e) {
return e
}
};
用法:await getDirRecursive("./public");
答案 19 :(得分:1)
这是一个简单的同步递归解决方案
const fs = require('fs')
const getFiles = path => {
const files = []
for (const file of fs.readdirSync(path)) {
const fullPath = path + '/' + file
if(fs.lstatSync(fullPath).isDirectory())
getFiles(fullPath).forEach(x => files.push(file + '/' + x))
else files.push(file)
}
return files
}
用法:
const files = getFiles(process.cwd())
console.log(files)
您可以异步编写它,但没有必要。只需确保输入目录存在且可访问。
答案 20 :(得分:1)
使用bluebird promise.coroutine:
let promise = require('bluebird'),
PC = promise.coroutine,
fs = promise.promisifyAll(require('fs'));
let getFiles = PC(function*(dir){
let files = [];
let contents = yield fs.readdirAsync(dir);
for (let i = 0, l = contents.length; i < l; i ++) {
//to remove dot(hidden) files on MAC
if (/^\..*/.test(contents[i])) contents.splice(i, 1);
}
for (let i = 0, l = contents.length; i < l; i ++) {
let content = path.resolve(dir, contents[i]);
let contentStat = yield fs.statAsync(content);
if (contentStat && contentStat.isDirectory()) {
let subFiles = yield getFiles(content);
files = files.concat(subFiles);
} else {
files.push(content);
}
}
return files;
});
//how to use
//easy error handling in one place
getFiles(your_dir).then(console.log).catch(err => console.log(err));
答案 21 :(得分:1)
我必须将基于Promise的sander库添加到列表中。
Sub Hide_Dates()
Dim This_Year As Range
Dim CD As Date
Dim SD As Date
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Set This_Year = Range("A5:A3000")
This_Year.EntireRow.Hidden = False
'Starts rows down
i = 5
'Current date
'CD = Format(Date, "dddd, mmmm dd,yyyy")
CD = DateSerial(Today.Year, Today.Month, Today.Day)
Do Until Cells(i, 1) = CD
'SD = Selected Date in the loop
SD = Cells(i, 1).Value 'Not sure how to DateSerial this!!!!
Debug.Print i
Debug.Print SD
Debug.Print CD
'Hides past days
If SD < CD Or SD = "" Then
Rows(i).EntireRow.Hidden = True
End If
i = i + 1
Loop
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
答案 22 :(得分:1)
使用Promises(Q)以功能样式解决此问题:
var fs = require('fs'),
fsPath = require('path'),
Q = require('q');
var walk = function (dir) {
return Q.ninvoke(fs, 'readdir', dir).then(function (files) {
return Q.all(files.map(function (file) {
file = fsPath.join(dir, file);
return Q.ninvoke(fs, 'lstat', file).then(function (stat) {
if (stat.isDirectory()) {
return walk(file);
} else {
return [file];
}
});
}));
}).then(function (files) {
return files.reduce(function (pre, cur) {
return pre.concat(cur);
});
});
};
它返回数组的承诺,因此您可以将其用作:
walk('/home/mypath').then(function (files) { console.log(files); });
答案 23 :(得分:1)
我修改了Trevor Senior的承诺回答,以便与Bluebird
一起使用var fs = require('fs'),
path = require('path'),
Promise = require('bluebird');
var readdirAsync = Promise.promisify(fs.readdir);
var statAsync = Promise.promisify(fs.stat);
function walkFiles (directory) {
var results = [];
return readdirAsync(directory).map(function(file) {
file = path.join(directory, file);
return statAsync(file).then(function(stat) {
if (stat.isFile()) {
return results.push(file);
}
return walkFiles(file).then(function(filesInDir) {
results = results.concat(filesInDir);
});
});
}).then(function() {
return results;
});
}
//use
walkDir(__dirname).then(function(files) {
console.log(files);
}).catch(function(e) {
console.error(e); {
});
答案 24 :(得分:1)
此处另一个实施。以上解决方案都没有任何限制因素,因此如果您的目录结构很大,那么它们将全部捶打并最终耗尽资源。
var async = require('async');
var fs = require('fs');
var resolve = require('path').resolve;
var scan = function(path, concurrency, callback) {
var list = [];
var walker = async.queue(function(path, callback) {
fs.stat(path, function(err, stats) {
if (err) {
return callback(err);
} else {
if (stats.isDirectory()) {
fs.readdir(path, function(err, files) {
if (err) {
callback(err);
} else {
for (var i = 0; i < files.length; i++) {
walker.push(resolve(path, files[i]));
}
callback();
}
});
} else {
list.push(path);
callback();
}
}
});
}, concurrency);
walker.push(path);
walker.drain = function() {
callback(list);
}
};
使用50的并发性非常好,并且几乎与小目录结构的简单实现一样快。
答案 25 :(得分:1)
recursive-readdir模块具有此功能。
答案 26 :(得分:0)
因为每个人都应该写自己的,我做了一个。
走路(dir,cb,endCb) CB(文件) endCb(err | null)
DIRTY
module.exports = walk;
function walk(dir, cb, endCb) {
var fs = require('fs');
var path = require('path');
fs.readdir(dir, function(err, files) {
if (err) {
return endCb(err);
}
var pending = files.length;
if (pending === 0) {
endCb(null);
}
files.forEach(function(file) {
fs.stat(path.join(dir, file), function(err, stats) {
if (err) {
return endCb(err)
}
if (stats.isDirectory()) {
walk(path.join(dir, file), cb, function() {
pending--;
if (pending === 0) {
endCb(null);
}
});
} else {
cb(path.join(dir, file));
pending--;
if (pending === 0) {
endCb(null);
}
}
})
});
});
}
答案 27 :(得分:0)
检查loaddir https://npmjs.org/package/loaddir
npm install loaddir
loaddir = require('loaddir')
allJavascripts = []
loaddir({
path: __dirname + '/public/javascripts',
callback: function(){ allJavascripts.push(this.relativePath + this.baseName); }
})
如果您还需要扩展程序,则可以使用fileName
代替baseName
。
额外的好处是它也会观看文件并再次调用回调。有很多配置选项可以使它非常灵活。
我只是在短时间内使用loaddir从ruby重新制作guard
gem
答案 28 :(得分:0)
有一个名为 cup-readdir 的新模块,它可以非常快速地递归搜索目录。在处理深层目录结构时,它使用异步承诺并优于许多流行的模块。
它可以返回数组中的所有文件并按其属性对它们进行排序,但缺少文件过滤和输入符号链接目录等功能。这对于您只想从目录中获取每个文件的大型项目可能很有用。这是他们项目主页的 link。
答案 29 :(得分:0)
只需步行
let pending = [baseFolderPath]
function walk () {
pending.shift();
// do stuffs width pending[0] and change pending items
if (pending[0]) walk(pending[0])
}
walk(pending[0])
答案 30 :(得分:0)
这是我的答案。希望它可以帮助某人。
我的重点是让搜索例程可以在任何地方停止,对于找到的文件,它会告诉原始路径的相对深度。
var _fs = require('fs');
var _path = require('path');
var _defer = process.nextTick;
// next() will pop the first element from an array and return it, together with
// the recursive depth and the container array of the element. i.e. If the first
// element is an array, it'll be dug into recursively. But if the first element is
// an empty array, it'll be simply popped and ignored.
// e.g. If the original array is [1,[2],3], next() will return [1,0,[[2],3]], and
// the array becomes [[2],3]. If the array is [[[],[1,2],3],4], next() will return
// [1,2,[2]], and the array becomes [[[2],3],4].
// There is an infinity loop `while(true) {...}`, because I optimized the code to
// make it a non-recursive version.
var next = function(c) {
var a = c;
var n = 0;
while (true) {
if (a.length == 0) return null;
var x = a[0];
if (x.constructor == Array) {
if (x.length > 0) {
a = x;
++n;
} else {
a.shift();
a = c;
n = 0;
}
} else {
a.shift();
return [x, n, a];
}
}
}
// cb is the callback function, it have four arguments:
// 1) an error object if any exception happens;
// 2) a path name, may be a directory or a file;
// 3) a flag, `true` means directory, and `false` means file;
// 4) a zero-based number indicates the depth relative to the original path.
// cb should return a state value to tell whether the searching routine should
// continue: `true` means it should continue; `false` means it should stop here;
// but for a directory, there is a third state `null`, means it should do not
// dig into the directory and continue searching the next file.
var ls = function(path, cb) {
// use `_path.resolve()` to correctly handle '.' and '..'.
var c = [ _path.resolve(path) ];
var f = function() {
var p = next(c);
p && s(p);
};
var s = function(p) {
_fs.stat(p[0], function(err, ss) {
if (err) {
// use `_defer()` to turn a recursive call into a non-recursive call.
cb(err, p[0], null, p[1]) && _defer(f);
} else if (ss.isDirectory()) {
var y = cb(null, p[0], true, p[1]);
if (y) r(p);
else if (y == null) _defer(f);
} else {
cb(null, p[0], false, p[1]) && _defer(f);
}
});
};
var r = function(p) {
_fs.readdir(p[0], function(err, files) {
if (err) {
cb(err, p[0], true, p[1]) && _defer(f);
} else {
// not use `Array.prototype.map()` because we can make each change on site.
for (var i = 0; i < files.length; i++) {
files[i] = _path.join(p[0], files[i]);
}
p[2].unshift(files);
_defer(f);
}
});
}
_defer(f);
};
var printfile = function(err, file, isdir, n) {
if (err) {
console.log('--> ' + ('[' + n + '] ') + file + ': ' + err);
return true;
} else {
console.log('... ' + ('[' + n + '] ') + (isdir ? 'D' : 'F') + ' ' + file);
return true;
}
};
var path = process.argv[2];
ls(path, printfile);
答案 31 :(得分:0)
在TypeScript中使用Array.flat()处理嵌套返回的基于约定的递归解决方案。
import { resolve } from 'path'
import { Dirent } from 'fs'
import * as fs from 'fs'
function getFiles(root: string): Promise<string[]> {
return fs.promises
.readdir(root, { withFileTypes: true })
.then(dirents => {
const mapToPath = (r: string) => (dirent: Dirent): string => resolve(r, dirent.name)
const directoryPaths = dirents.filter(a => a.isDirectory()).map(mapToPath(root))
const filePaths = dirents.filter(a => a.isFile()).map(mapToPath(root))
return Promise.all<string>([
...directoryPaths.map(a => getFiles(a, include)).flat(),
...filePaths.map(a => Promise.resolve(a))
]).then(a => a.flat())
})
}
答案 32 :(得分:0)
为此有一个NPM模块:
npm dree
它遍历该对象的所有目录树,并将其作为字符串或对象返回。使用其文件回调将使您实现目标。
示例:
const dree = require('dree');
const options = {
followLinks: true, // If you want to follow the folders pointed by symbolic links
depth: 5, // If you want to stop after 5 directory levels
exclude: /dir_to_exclude/, // If you want to exclude some pahts with a regexp
extensions: [ 'txt', 'jpg' ] // If you want only some extensions
};
const paths = [];
const fileCallback = function (file) {
paths.push(file.relativePath);
};
let tree;
// Do it synchronously
tree = dree.scan('./dir', options, fileCallback);
// Do it asynchronously (returns promise)
tree = await dree.scanAsync('./dir', options, fileCallback);
// Now paths contains the paths you want
console.log(paths);
// tree contains an object representing the directory tree (filtered in base of the conditions)
请注意,如果您使用await,则此代码应包含在异步函数中。返回了promise,因此您可以使用.then()方法。
答案 33 :(得分:0)
异步
const fs = require('fs')
const path = require('path')
const readdir = (p, done, a = [], i = 0) => fs.readdir(p, (e, d = []) =>
d.map(f => readdir(a[a.push(path.join(p, f)) - 1], () =>
++i == d.length && done(a), a)).length || done(a))
readdir(__dirname, console.log)
同步
const fs = require('fs')
const path = require('path')
const readdirSync = (p, a = []) => {
if (fs.statSync(p).isDirectory())
fs.readdirSync(p).map(f => readdirSync(a[a.push(path.join(p, f)) - 1], a))
return a
}
console.log(readdirSync(__dirname))
异步可读
function readdir (currentPath, done, allFiles = [], i = 0) {
fs.readdir(currentPath, function (e, directoryFiles = []) {
if (!directoryFiles.length)
return done(allFiles)
directoryFiles.map(function (file) {
var joinedPath = path.join(currentPath, file)
allFiles.push(joinedPath)
readdir(joinedPath, function () {
i = i + 1
if (i == directoryFiles.length)
done(allFiles)}
, allFiles)
})
})
}
readdir(__dirname, console.log)
注意:两个版本都将遵循符号链接(与原始fs.readdir
相同)
答案 34 :(得分:0)
对于Node 10.3+,这是一个for-await解决方案:
#!/usr/bin/env node
const FS = require('fs');
const Util = require('util');
const readDir = Util.promisify(FS.readdir);
const Path = require('path');
async function* readDirR(path) {
const entries = await readDir(path,{withFileTypes:true});
for(let entry of entries) {
const fullPath = Path.join(path,entry.name);
if(entry.isDirectory()) {
yield* readDirR(fullPath);
} else {
yield fullPath;
}
}
}
async function main() {
const start = process.hrtime.bigint();
for await(const file of readDirR('/mnt/home/media/Unsorted')) {
console.log(file);
}
console.log((process.hrtime.bigint()-start)/1000000n);
}
main().catch(err => {
console.error(err);
});
此解决方案的好处是您可以立即开始处理结果;例如读取媒体目录中的所有文件需要12秒钟,但是如果以这种方式进行操作,则可以在几毫秒内获得第一个结果。
答案 35 :(得分:0)
又一个答案,但这次使用的是TypeScript:
/**
* Recursively walk a directory asynchronously and obtain all file names (with full path).
*
* @param dir Folder name you want to recursively process
* @param done Callback function, returns all files with full path.
* @param filter Optional filter to specify which files to include,
* e.g. for json files: (f: string) => /.json$/.test(f)
*/
const walk = (
dir: string,
done: (err: Error | null, results ? : string[]) => void,
filter ? : (f: string) => boolean
) => {
let results: string[] = [];
fs.readdir(dir, (err: Error, list: string[]) => {
if (err) {
return done(err);
}
let pending = list.length;
if (!pending) {
return done(null, results);
}
list.forEach((file: string) => {
file = path.resolve(dir, file);
fs.stat(file, (err2, stat) => {
if (stat && stat.isDirectory()) {
walk(file, (err3, res) => {
if (res) {
results = results.concat(res);
}
if (!--pending) {
done(null, results);
}
}, filter);
} else {
if (typeof filter === 'undefined' || (filter && filter(file))) {
results.push(file);
}
if (!--pending) {
done(null, results);
}
}
});
});
});
};
答案 36 :(得分:0)
这就是我使用nodejs fs.readdir函数递归搜索目录的方法。
const fs = require('fs');
const mime = require('mime-types');
const readdirRecursivePromise = path => {
return new Promise((resolve, reject) => {
fs.readdir(path, (err, directoriesPaths) => {
if (err) {
reject(err);
} else {
if (directoriesPaths.indexOf('.DS_Store') != -1) {
directoriesPaths.splice(directoriesPaths.indexOf('.DS_Store'), 1);
}
directoriesPaths.forEach((e, i) => {
directoriesPaths[i] = statPromise(`${path}/${e}`);
});
Promise.all(directoriesPaths).then(out => {
resolve(out);
}).catch(err => {
reject(err);
});
}
});
});
};
const statPromise = path => {
return new Promise((resolve, reject) => {
fs.stat(path, (err, stats) => {
if (err) {
reject(err);
} else {
if (stats.isDirectory()) {
readdirRecursivePromise(path).then(out => {
resolve(out);
}).catch(err => {
reject(err);
});
} else if (stats.isFile()) {
resolve({
'path': path,
'type': mime.lookup(path)
});
} else {
reject(`Error parsing path: ${path}`);
}
}
});
});
};
const flatten = (arr, result = []) => {
for (let i = 0, length = arr.length; i < length; i++) {
const value = arr[i];
if (Array.isArray(value)) {
flatten(value, result);
} else {
result.push(value);
}
}
return result;
};
我们假设您有一条名为&#39; / database&#39;在您的节点项目根目录中。一旦这个承诺得到解决,它就应该在&#39; / database&#39;下面吐出每个文件的数组。
readdirRecursivePromise('database').then(out => {
console.log(flatten(out));
}).catch(err => {
console.log(err);
});
答案 37 :(得分:0)
另一个简单而有用的
function walkDir(root) {
const stat = fs.statSync(root);
if (stat.isDirectory()) {
const dirs = fs.readdirSync(root).filter(item => !item.startsWith('.'));
let results = dirs.map(sub => walkDir(`${root}/${sub}`));
return [].concat(...results);
} else {
return root;
}
}
答案 38 :(得分:0)
这是获取所有文件(包括子目录)的递归方法。
const FileSystem = require("fs");
const Path = require("path");
//...
function getFiles(directory) {
directory = Path.normalize(directory);
let files = FileSystem.readdirSync(directory).map((file) => directory + Path.sep + file);
files.forEach((file, index) => {
if (FileSystem.statSync(file).isDirectory()) {
Array.prototype.splice.apply(files, [index, 1].concat(getFiles(file)));
}
});
return files;
}
答案 39 :(得分:-1)
这是完整的工作代码。根据您的要求。你可以递归地获取所有文件和文件夹。
var recur = function(dir) {
fs.readdir(dir,function(err,list){
list.forEach(function(file){
var file2 = path.resolve(dir, file);
fs.stat(file2,function(err,stats){
if(stats.isDirectory()) {
recur(file2);
}
else {
console.log(file2);
}
})
})
});
};
recur(path);
路径中的为您提供要搜索的目录路径,例如&#34; c:\ test&#34;