【问题标题】:Read and parse CSV file in S3 without downloading the entire file在 S3 中读取和解析 CSV 文件,无需下载整个文件
【发布时间】:2017-02-13 03:32:07
【问题描述】:

使用 node.js,目的是将此模块作为 AWS Lambda 函数运行。

使用 aws-sdk 中的 s3.getObject(),我能够成功地从 Amazon S3 中获取一个非常大的 CSV 文件。目的是读取文件中的每一行,并在每一行的正文中发出一个事件。

在我能找到的所有示例中,看起来 S3 中的整个 CSV 文件必须被缓冲或流式传输,转换为字符串,然后逐行读取。

s3.getObject(params, function(err, data) {
   var body = data.Body.toString('utf-8');
}

考虑到源 CSV 文件的大小,此操作需要很长时间。此外,CSV 行的长度不同,我不确定是否可以使用缓冲区大小作为选项。

问题

有没有办法在 node.js 中提取 S3 文件并逐行读取/转换它,从而避免首先在内存中对整个文件进行字符串化?

理想情况下,我更愿意使用fast-csv 和/或node-csv 的更好功能,而不是手动循环。

【问题讨论】:

    标签: node.js amazon-web-services amazon-s3 aws-sdk


    【解决方案1】:

    对我来说,解决我的问题的答案是,

      const csv = require('@fast-csv/parse');
    
      const params = {
        Bucket: srcBucket,
        Key: srcKey,
      };
      const csvFile = s3.getObject(params).createReadStream();
    
      let parserFcn = new Promise((resolve, reject) => {
        const parser = csv
          .parseStream(csvFile, { headers: true })
          .on("data", function (data) {
            console.log('Data parsed: ', data);
          })
          .on("end", function () {
            resolve("csv parse process finished");
          })
          .on("error", function () {
            reject("csv parse process failed");
          });
      });
    
      try {
        await parserFcn;
      } catch (error) {
        console.log("Get Error: ", error);
      }
    

    【讨论】:

      【解决方案2】:

      我没有足够的声誉来发表评论,但到目前为止,“fast-csv”不存在可接受的答案方法“fromStream”。现在你需要使用parseStream 方法:

      const s3Stream = s3.getObject(params).createReadStream()
      require('fast-csv').parseStream(s3Stream)
        .on('data', (data) => {
          // use rows
        })
      

      【讨论】:

      • 感谢您添加此内容。我一直在寻找它。 :)
      【解决方案3】:

      您应该能够使用createReadStream method 并将其通过管道传输到 fast-csv:

      const s3Stream = s3.getObject(params).createReadStream()
      require('fast-csv').fromStream(s3Stream)
        .on('data', (data) => {
          // do something here
        })
      

      【讨论】:

      • 这很好用。只是补充一下,如果您有兴趣知道解析何时结束,请添加.on('end' () => { //Your handling })
      • @DeepakGM 你忘了逗号.on('end', () => { })
      • 此方法已被弃用,请参阅下面我的回答,以改用 parseStream 方法
      • 什么版本的 lib 包含 fromStream ? parseStream 抛出一个错误......
      【解决方案4】:

      不是逐行,但您可以使用 Range 标头按字节范围获取 S3 对象。因此,您可以一次读取 1000 个字节,并在读取数据时管理您端的新行。查看 GET Object documentation 并搜索 Range 标头。

      【讨论】:

        猜你喜欢
        • 2019-07-09
        • 2021-11-22
        • 1970-01-01
        • 1970-01-01
        • 2011-07-18
        • 2012-06-08
        • 2021-03-21
        相关资源
        最近更新 更多