读取多个目录中的文件,使用 Node 和 Promises 将文件名与其数据匹配
Reading files in multiple directories, matching filenames with their data using Node and Promises
我有一个目录数组。
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。
我不知道 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);
});
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;
}, {}));
}
我有一个目录数组。
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。
我不知道 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);
});
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;
}, {}));
}