使用Lambda(NodeJS)在S3上的gzip存档中读取制表符分隔的文件

时间:2019-11-20 23:50:26

标签: node.js amazon-s3 aws-lambda

我有以下用例要解决。我需要使用Lambda函数(NodeJS 12)从S3存储桶中提取数据。创建新文件时将触发Lambda函数。该文件是gz归档文件,可以包含多个TSV(制表符分隔)文件。对于每一行,将从Lambda函数触发API调用。问题:

1-是否必须执行两个步骤:将压缩文件解压缩到/ tmp文件夹中,然后读取TSV文件。还是可以直接流式传输存档文件的内容?

2-您是否可以共享一小段代码,以显示如何从S3存储桶及其内容(TSV)中流式传输GZ文件?我发现了几个示例,但仅适用于纯NodeJS。不是来自Lambda / S3。

非常感谢您的帮助。

为我的第一个测试添加一小段代码,但是它不起作用。控制台中未记录任何数据

const csv = require('csv-parser')
const aws = require('aws-sdk');
const s3 = new aws.S3();


exports.handler = async(event, context, callback) => {
    const bucket = event.Records[0].s3.bucket.name;
    const objectKey = event.Records[0].s3.object.key;
    const params = { Bucket: bucket, Key: objectKey };
    var results = [];

    console.log("My File: "+objectKey+"\n")
    console.log("My Bucket: "+bucket+"\n")


    var otherOptions = {
        columns: true,
        auto_parse: true,
        escape: '\\',
        trim: true,
    };

    s3.getObject(params).createReadStream()
        .pipe(csv({ separator: '|' }))
        .on('data', (data) => results.push(data))
        .on('end', () => {
            console.log("My data: "+results);
        });

    return await results
};


2 个答案:

答案 0 :(得分:0)

您可能想看看wiki

  

尽管其文件格式还允许将多个[压缩文件/数据流]串联在一起(压缩后的文件就像原来是一个文件一样被简单地解压缩并串联在一起[5]),但gzip通常用于仅压缩单个文件。压缩档案通常是通过将文件集合组装到一个tar档案(也称为tarball)中,然后使用gzip压缩该档案来创建的。最终的压缩文件通常具有扩展名.tar.gz或.tgz。

这意味着gzip(或使用它的Node包)本身的功能不足以将单个.gz文件解压缩为多个文件。我希望,如果S3中的一个.gz项包含多个文件,则实际上是.tar.gz或类似的压缩集合。要处理这些,请查看

Simplest way to download and unzip files in NodeJS

您可能还对node-tar感兴趣。

就一次只从存档中取出一个文件而言,这取决于压缩的集合实际是什么。有些压缩方案一次只能提取一个文件,而其他压缩方案则不允许(它们一次压缩整个文件)。 Tar does the former

答案 1 :(得分:0)

第一步应该是解压 .tar.gz 文件,使用包 decompress

// typescript code for decompressing .tar.gz file
const decompress = require("decompress");
try {
  const targzSrc = await aws.s3
    .getObject({
      Bucket: BUCKET_NAME,
      Key: fileRequest.key
    });


  const filesPromise = decompress(targzSrc.Body);
  const outputFileAsString = await filesPromise.then((files: any) => {
    console.log("inflated file:", files["0"].data.toString("utf-8"));
    return files["0"].data.toString("utf-8");
  });
  
  console.log("And here goes the file content:", outputFileAsString);

  // here should be the code that parses the CSV content using the outputFileAsString

} catch (err) {
  console.log("G_ERR:", err);
}