读取多个目录中的文件,使用 Node 和 Promises 将文件名与其数据匹配
Posted
技术标签:
【中文标题】读取多个目录中的文件,使用 Node 和 Promises 将文件名与其数据匹配【英文标题】:Reading files in multiple directories, matching filenames with their data using Node and Promises 【发布时间】:2015-07-08 23:58:37 【问题描述】:我有一个目录数组。
var directories = ['/dir1', '/dir2'];
我想读取这些目录下的所有文件,最后有一个将文件名与其 base64/utf8 数据匹配的对象。就我而言,这些文件是图像。生成的对象可能如下所示:
var result =
'/dir1':
'file1': 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAIAAACx0UUtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWF...',
'file2': 'iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAIAAACx0UUtAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWF...'
我通过回调地狱轻松实现了这一点,但是当我尝试使用 Promises 时,我不确定如何将目录信息和文件名传递给后续的 then() 和 map() 函数。
在下面的示例中,我使用的是 Bluebird 库:
const Promise = require('bluebird'),
fs = Promise.promisifyAll(require('fs'));
var getFiles = function (dir)
return fs.readdirAsync(dir);
;
Promise.map(directories, function(directory)
return getFiles(directory)
).map(function (files)
// which directory's files are these?
return files;
)
下一步是遍历文件并读取它们的数据。
我不介意答案是 ES6、Bluebird 还是 Q。
【问题讨论】:
为什么在数组上使用_.keys(directories)
?
@Bergi 打错了,抱歉,现在已编辑。
@DenizOzger 你对递归路径解析和嵌套目录感兴趣吗?
@BenjaminGruenbaum 是的,只要我可以将文件数据映射到文件名并将文件名映射到目录,什么都可以。
@DenizOzger 你用的是什么版本的node/io?
【参考方案1】:
我不知道 Bluebird,但这是 ES6 Promise 方法。
var fs = require('fs');
var directories = ['/dir1', '/dir2'];
var result = ;
Promise.all(directories.map(function(dir)
result[dir] = ;
return new Promise(function(resolve, reject)
fs.readdir(dir, function(er, files)
if (er)
return reject(er);
resolve(files);
);
).then(function(files)
return Promise.all(files.map(function(file)
return new Promise(function(resolve, reject)
fs.readFile(dir + '/' + file, function(er, data)
if (er)
return reject(er);
result[dir][file] = data.toString('base64');
resolve();
);
);
));
);
)).then(function()
console.log(result);
).catch(function(er)
console.log(er);
);
【讨论】:
不要使用promise constructor antipattern! 非常感谢@Tresdin 的回答,我了解它的工作原理并欣赏 ES6 方法,但我有点失望,因为它看起来像是我试图避免的回调地狱。 @DenizOzger 是的,我也是。我实际上更喜欢async
模块,因为它更快更容易阅读。 :)
哇,我很高兴我现在正在使用 bluebird。蓝鸟更好。【参考方案2】:
使用 Bluebird 最简单的方法是使用 props
:
function getFiles(paths) // an array of file/directory paths
return Promise.props(paths.reduce(function (obj, path)
obj[path.split("/").pop()] = fs.statAsync(path).then(function (stat)
if (stat.isDirectory())
return fs.readdirAsync(path).map(function (p)
return path + "/" + p;
).then(getFiles);
else if (stat.isFile())
return fs.readFileAsync(path);
).error(function (e)
console.error("unable to read " + path + ", because: ", e.message);
// return undefined; implied
);
return obj;
, ));
【讨论】:
第三行有TypeError: Cannot read property 'then' of undefined
。我们的 fs 定义是否相同? IE。 fs = Promise.promisifyAll(require('fs'))
是的,当然应该是fs.statAsync
:-)
当然 :) 我将这个数组:['/dir1', '/dir2']
传递给函数。在第一次执行 .reduce() 回调时,obj 为
,path 为'/dir1'
。第二次执行时,obj为undefined
,path为'/dir2'
。这最终出现在Cannot set property '/dir2' of undefined
reduce 函数不是这个吗?:developer.mozilla.org/en/docs/Web/javascript/Reference/…
我的意思是,如果在枚举过程中添加了文件/目录,它将在这里中断(如果它在统计数据中并且不存在 - 因为服务器会更改内容)。
好的,最新的代码编辑似乎已经解决了以上是关于读取多个目录中的文件,使用 Node 和 Promises 将文件名与其数据匹配的主要内容,如果未能解决你的问题,请参考以下文章
[从`prom-client`模块导入`prom`,但已安装。如何“相应地导入prom-client”?