繁体   English   中英

Node.js查找具有相同内容异步的文件

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM