简体   繁体   English

如何从Node.js中的Amazon S3存储桶同步下载文件

[英]How to download a file from Amazon S3 bucket in node.js synchronously

I have to download multiple files from S3 bucket using node.js. 我必须使用node.js从S3存储桶下载多个文件。 For that I have to write a for loop & call the s3.getObject(param) method to download. 为此,我必须编写一个for loop并调用s3.getObject(param)方法进行下载。 After the files are downloaded I have to merge their contents. 下载文件后,我必须合并其内容。

I have written like this: 我这样写:

var fileContentList = new ArrayList();

for(i=0; i<fileNameList.length i++){
    s3.getObject({ Bucket: "my-bucket", Key: fileNameList.get(i) }, function (error, data) {
    if (error != null) {
      alert("Failed to retrieve an object: " + error);
    } else {
      alert("Loaded " + data.ContentLength + " bytes");
      fileContentList.add(data.Body.toString());
    }
  }
);
}

//Do merging with the fileContentList.

But as s3.getObject is an asynchronous call the current thread moves on & nothing gets added to the fileContentList while I am doing the merging. 但是由于s3.getObject是一个异步调用,所以当执行合并时,当前线程继续s3.getObject并且没有任何内容添加到fileContentList

How can I solve the problem? 我该如何解决这个问题? Any idea? 任何想法?
Is their any synchronous method in aws-sdk to download file? 在aws-sdk中是否有任何同步方法来下载文件?

Promises is better way, 承诺是更好的方法,

var getObject = function(keyFile) {
    return new Promise(function(success, reject) {
        s3.getObject(
            { Bucket: "my-bucket", Key: keyFile },
            function (error, data) {
                if(error) {
                    reject(error);
                } else {
                    success(data);
                }
            }
        );
    });
}

var promises = [];
var fileContentList = new ArrayList();

for(i=0; i<fileNameList.length i++){
    promises.push(getObject(fileNameList.get(i)));
}

Promise.all(promises)
.then(function(results) {
    for(var index in results) {
        var data = results[index];
        fileContentList.add(data.Body.toString());
    }
    // continue your process here
})
.catch(function(err) {
    alert(err);
});

You can use here async each, it will download all the files in parallel. 您可以在此处每个使用async,它将并行下载所有文件。 In this example the download will continue if some of the files failed, if you want to stop downloading the files once an error occurred, call the callback with the error, this will call to the final callback immediately. 在此示例中,如果某些文件失败,下载将继续,如果您想在发生错误后停止下载文件,请调用带有错误的回调,这将立即调用最终的回调。

async documentation 异步文档

var async = require('async');
var fileContentList = new ArrayList();
function downloadS3Multiple(done){
    async.each([
            function (callback) {
                s3.getObject({Bucket: "my-bucket", Key: fileNameList.get(i)}, function (err, res) {
                    if (err) {
                        alert("Failed to retrieve an object: " + error);
                        callback();
                    }
                    else {
                        alert("Loaded " + data.ContentLength + " bytes");
                        fileContentList.add(data.Body.toString());
                        callback();

                    }
                })
            }
        ], function (err, results) {
            done(err, fileContentList)
        });
}

Keep track of downloads you initiated in a separate list and as each download completes check to see if they are all done. 在单独的列表中跟踪您启动的下载,并在每次下载完成后检查是否全部完成。

var fileContentList = new ArrayList();
var completedList = new ArrayList();
// function to setDone and initiate merge if all download attempts completed.
function setDone(i) {
    completedList[i]=true;
    var allDone= true;
    for(i=0; i<completedList.length && allDone=completedList[i] && allDone; i++);
    if(allDone) {
       mergeFiles();
    }
}

// fill completedList with a false value for each fill to be downloaded
for(i=0; i<fileNameList.length;i++) completedList.add(false);

// initiate the downloads
for(i=0; i<fileNameList.length; i++){
    s3.getObject({ Bucket: "my-bucket", Key: fileNameList.get(i) }, function (error, data) {
    if (error != null) {
      alert("Failed to retrieve an object: " + error);
    } else {
      alert("Loaded " + data.ContentLength + " bytes");
      fileContentList.add(data.Body.toString());
    }
    setDone(i);
  }
);
}

A more elegant solution, if you only want to merge the files if all downloads complete successfully: 如果您只想在所有下载成功完成后合并文件,则是一个更优雅的解决方案:

var fileContentList = new ArrayList();

for(i=0; i<fileNameList.length i++){
    s3.getObject({ Bucket: "my-bucket", Key: fileNameList.get(i) }, function (error, data) {
    if (error != null) {
      alert("Failed to retrieve an object: " + error);
    } else {
      alert("Loaded " + data.ContentLength + " bytes");
      fileContentList.add(data.Body.toString());
    }
    if(fileContentList.length==fileNameList.length) combineFiles();
  }
);
}

I have solved using this. 我已经解决了使用此。 Though I have not tried the answers of Alexander,Lena & Sébastian I believe each of the answers mentioned by them would also work in this case. 尽管我尚未尝试过Alexander,Lena和Sébastian的答案,但我相信他们提到的每个答案在这种情况下也都适用。 Many many thanks to them for their quick reply: 非常感谢他们的快速回复:

Async.eachSeries(casCustomersList, function (customerName, next){
        if(casCustomersList.length>0 && customerName != customerId) {

            var paramToAws = {
                Bucket: bucketName,
                Key: folderPath +'applicationContext-security-' + customerName + '.xml'      //file name
            };
            AWSFileAccessManager.downloadFile(paramToAws, function (error, result) {
                if (error) {
                    next(error);
                } else {
                    customerApplicationContext.add(result.Body.toString());
                    next();
                }

            });
        } else{
            next();
        }

    }, function(err) {
       //Write the rest of your logic here to process synchronously as it is the callback function

    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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