[英]Node.js find a file with the same content async
目标:给定输入中的文件路径和文件路径数组,我需要检查数组中是否有一个文件(即使名称不同)也等于输入文件。 我需要异步读取文件,如果找到相等的文件,则停止读取(在这种情况下,我不想读取数组中的所有文件)。
我只想使用ecma6功能,而没有其他库。 我正在使用node.js,因此要比较文件就足以使用比较缓冲区功能 :
const fs = require("fs");
let buffer1 = fs.readFileSync(filePath1);
let buffer2 = fs.readFileSync(filePath2);
if (buffer1.compare(buffer2) === 0) {
console.log("Files are equal");
} else {
console.log("Files are different");
}
基本上,对于数组中的每个文件路径,我都想使用如下功能按顺序检查相等性(但使用异步读取):
function isFileEqual (fileInputBuffer, path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) {
resolve(false);
}
if (data.compare(fileInputBuffer) === 0) {
resolve(true);
} else {
resolve(false);
}
});
});
}
我想出了一个利用Promises.all的“快速拒绝”属性的解决方案,如果任何输入的Promise都被拒绝,而没有等待其他Promise的完成,那么它会立即被拒绝:
const fs = require("fs");
let paths = ["file2", "file3", "file1_copy", "file4", "file5"];
checkIfFileAlreadyExistsAsync("file1", paths).then(path => {
console.log("\n", "File equal found at: ", path, "\n");
}).catch(err => {
console.log(err);
});
function checkIfFileAlreadyExistsAsync(filePath, paths) {
return new Promise( (rootResolve, rootReject) => {
fs.readFile(filePath, (err, inputBuffer) => {
if (err) {
rootReject(err);
return;
}
function isFileEqual(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
console.log("[isFileEqual]", path);
if (err) {
resolve();
}
else if (data.compare(inputBuffer) === 0) {
reject(path); // file equal found, reject fast!
} else {
resolve();
}
});
});
}
let promises = [];
// fill promises array
paths.forEach(path => {
promises.push(isFileEqual(path));
})
Promise.all(promises).then(values => {
rootReject(false);
})
.catch((path) => {
// use reject fast to resolve without wait the other promises to complete
rootResolve(path);
});
});
});
}
上面脚本的输出:
[isFileEqual] file2
[isFileEqual] file1_copy
File equal found at: file1_copy
[isFileEqual] file4
[isFileEqual] file3
[isFileEqual] file5
上面的解决方案有效,但是如您所见,存在一个问题:始终读取所有文件,而不管是否已找到相等的文件。
我以前不知道,但是Promise会在创建后立即执行(我虽然相反,为什么以这种方式实现?),因此我在考虑使用promise工厂,如下所示:
function promiseFactory(path) {
return function () {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
console.log("[isFileEqual]", path);
if (err) {
reject();
}
else if (data.compare(inputBuffer) === 0) {
resolve(true);
} else {
resolve(false);
}
});
});
};
}
并尝试按顺序执行承诺。 但是我该怎么办呢? 还是有其他方法?
我找到了使用递归的解决方案。 基本上,我创建了一个工厂数组(每个工厂返回一个返回Promise的函数),然后将该数组用作递归函数的输入。 如果找到一个相等的文件,则递归函数解析主Promise(由主函数返回的那个Promise),否则它以输入数组工厂和下一个要创建的索引来递归调用自身。
const fs = require("fs");
let paths = ["file2", "file3", "file1_copy", "file4", "file5"];
checkIfFileAlreadyExistsAsync("file1", paths).then(result => {
console.log("SUCCESS", result);
}).catch(err => {
console.log("FAIL", err);
});
function checkIfFileAlreadyExistsAsync(filePath, paths) {
return new Promise((rootResolve, rootReject) => {
fs.readFile(filePath, (err, inputBuffer) => {
if (err) {
rootReject(err);
}
function compareFilePromiseFactory(path) {
return function() {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
console.log("Compare file: ", path, "\n");
if (err) {
resolve(false);
}
else if(data.compare(inputBuffer) === 0) {
resolve(true);
}
else {
resolve(false);
}
});
});
}
}
let factories = [];
paths.forEach(path => {
factories.push(compareFilePromiseFactory(path));
});
function findFile(factories, index) {
if (index == factories.length) {
rootReject(false);
return;
}
factories[index]().then(result => {
if (result) {
rootResolve(true);
}
else {
findFile(factories, index + 1);
}
});
}
findFile(factories, 0);
});
});
}
上面的脚本提供以下输出:
Compare file: file2
Compare file: file3
Compare file: file1_copy
SUCCESS true
每个promise是按顺序创建的,但是都是异步的。 一旦找到相等文件,它将停止生成promise。 我不知道是否也可以使用迭代解决方案,您认为呢?
无极种族
Promise.race是一个有趣的功能-Promise.race无需等待所有诺言被解决或拒绝,而是在阵列中的任何诺言被解决或拒绝时立即触发:
var req1 = new Promise(function(resolve, reject) {
// A mock async action using setTimeout
setTimeout(function() { resolve('First!'); }, 8000);
});
var req2 = new Promise(function(resolve, reject) {
// A mock async action using setTimeout
setTimeout(function() { resolve('Second!'); }, 3000);
});
Promise.race([req1, req2]).then(function(one) {
console.log('Then: ', one);
}).catch(function(one, two) {
console.log('Catch: ', one);
});
//从控制台://然后:第二!
选中此一项,相信会对您有所帮助
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.