解压缩文件并上传到S3

时间:2018-08-28 20:14:10

标签: javascript node.js aws-sdk etl

节点上的路由获取一个zip文件,然后从那里将其解压缩到内存中并将其上传到S3存储桶。一切工作正常,但是在zip文件中的所有文件都处理完后,我正在努力解决。

function unzipAndUploadToS3(fileInfo) {
    return new Promise((resolve, reject) => {
        fs.createReadStream(fileInfo.zip.path)
            .pipe(unzipper.Parse())
            .pipe(etl.map(entry => {
                if (checkEntry(entry.path)) {
                    fileInfo.name = entry.path;
                    entry
                        .buffer()
                        .then(content => {
                            fileInfo.data = content;
                            AWS.uploadToS3(fileInfo).then(result => {
                                console.log(result.Location);
                                resolve(result.Location);  //ALWAYS Resolves here
                            }).catch(err => {
                                console.error(err);
                                reject(err);
                            })
                        })
                }
                else
                    entry.autodrain();
            }))
    });
}

我已经尝试过Promise.all和Async / Await,但似乎可以绕开它。

2 个答案:

答案 0 :(得分:1)

我以前从未使用过NullPointerException,但是他们的documentation上有一条注释

  

从流切换到承诺链...

然后给出代码etl。您说您尝试过.promise().then(...),但是您没有说如何,所以我不知道您是否已经尝试过。但这是我认为事情可能会发展的方向:

Promise.all

尽管所有的Promise必须正确地链接在一起以进行条目缓冲,然后才能上载到s3,但此方法才能起作用。我标记了重要的回报,以保持带有评论的链接。

对我来说,还有一些其他问题:我不敢相信您可以继续将相同的function unzipAndUploadToS3(fileInfo) { return new Promise((resolve, reject) => { fs.createReadStream(fileInfo.zip.path) .pipe(unzipper.Parse()) .pipe(etl.map(entry => { if (checkEntry(entry.path)) { fileInfo.name = entry.path; return entry.buffer() //<- return promise .then(content => { fileInfo.data = content; return AWS.uploadToS3(fileInfo) //<- return promise }) } else entry.autodrain(); })) .promise().then(awsPromises => Promise.all(awsPromises)) //<- return promise .then(x => resolve('x should be an array of s3 results')) .catch(err => reject(err)); }); } 与多个文件重复使用。在我看来,这是一个竞争条件:上一个上传是否会在下一个文件覆盖fileInfofileInfo.data之前完成?我的猜测是,最好在地图内部创建一个新的fileInfo对象,而不是对zip中的所有文件重复使用相同的对象。

答案 1 :(得分:0)

这就是最终为我工作的原因。这会使用unziper,etl和lodash。

function unzipAndUploadToS3(fileInfo) {
    return new Promise((resolve, reject) => {
        var filesToProcess = [];
        var filesStream = fs.createReadStream(fileInfo.zip.path)
            .pipe(unzipper.Parse())
            .pipe(etl.map(entry => {
                if (checkEntry(entry.path)) {
                    fileInfo.name = entry.path.substr(entry.path.indexOf('/') + 1, entry.path.length);
                    entry
                        .buffer()
                        .then(content => {
                            fileInfo.data = content;
                            var newObj = _.clone(fileInfo);  //need to clone object because of object reference in assignment
                            var promise = new Promise(function(resolve, reject) {  //create new promise to upload to S3
                                AWS.uploadToS3(newObj).then(result => { //a function in another module uses aws-sdk
                                    resolve(result)
                                }).catch(err => reject(err));
                            })
                            filesToProcess.push(promise);  //push this promise into an array of promises
                        })
                }
                else
                    entry.autodrain();
            }))
        filesStream.on('readable',  function () { console.log('readable');  })
            .on('data',  function (data) { console.log('data', data);  })
            .on('error', function (err)  {
                console.error('Error', err);
                reject(err);
            })
            .on('end',   function ()     {
                Promise.all(filesToProcess).then(values => {    //process all the promises
                    console.log("values>", values);
                    resolve(values);
                }).catch(err => {reject(err)});
            })
    });
}