Node.js 查找具有相同内容异步的文件
Node.js find a file with the same content async
目标:给定输入文件路径和文件路径数组,我需要检查数组中是否存在与输入文件相同的文件(即使名称不同)。我需要异步读取文件并在找到相同文件时停止(在这种情况下我不想读取数组中的所有文件)。
我想只使用 ecma6 功能而不使用额外的库。
我正在使用 node.js,因此比较文件足以使用 compare buffers function:
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 的 "reject fast" 属性,这会导致立即拒绝,以防任何输入承诺在不等待其他输入的情况下被拒绝承诺完成:
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.race
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);
});
// 从控制台:
// 那么:第二个!
看看这个,相信对你有帮助
我找到了一个使用递归的解决方案。基本上我创建了一个工厂数组(每个工厂 returns 一个函数 returns 一个 Promise)然后使用该数组作为递归函数的输入。如果找到相同的文件,则递归函数解析主 Promise(由 main 函数返回的那个),否则它递归地调用自己,输入工厂数组和下一个要创建的承诺的索引。
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 都是按顺序创建的,但都是异步的。一旦找到相同的文件,它就会停止生成承诺。
不知道是否也可以迭代解决,你觉得呢?
目标:给定输入文件路径和文件路径数组,我需要检查数组中是否存在与输入文件相同的文件(即使名称不同)。我需要异步读取文件并在找到相同文件时停止(在这种情况下我不想读取数组中的所有文件)。
我想只使用 ecma6 功能而不使用额外的库。 我正在使用 node.js,因此比较文件足以使用 compare buffers function:
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 的 "reject fast" 属性,这会导致立即拒绝,以防任何输入承诺在不等待其他输入的情况下被拒绝承诺完成:
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.race
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);
});
// 从控制台: // 那么:第二个!
看看这个,相信对你有帮助
我找到了一个使用递归的解决方案。基本上我创建了一个工厂数组(每个工厂 returns 一个函数 returns 一个 Promise)然后使用该数组作为递归函数的输入。如果找到相同的文件,则递归函数解析主 Promise(由 main 函数返回的那个),否则它递归地调用自己,输入工厂数组和下一个要创建的承诺的索引。
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 都是按顺序创建的,但都是异步的。一旦找到相同的文件,它就会停止生成承诺。 不知道是否也可以迭代解决,你觉得呢?