如何在循环中获取 Amazon S3 对象?

Posted

技术标签:

【中文标题】如何在循环中获取 Amazon S3 对象?【英文标题】:How to get Amazon S3 objects in a loop? 【发布时间】:2018-11-01 04:22:18 【问题描述】:

在 Node.js 中,我尝试通过使用 fs.createReadStreamfs.createWriteStream 方法循环遍历数组来检索对象。

AWS 文档展示了如何使用 s3.getObject(params).createReadStream().pipe(file);

但是将参数和 Amazon S3 设置为

  const params =  Bucket:'user_events' ;
  const s3 = new AWS.S3();

当我调用我的函数时:

  function gets3Objects(eventsArray) 
    console.log('--> finding files from s3...');
    const arrLen = eventsArray.length;
    let iter = 0;

    s3.listObjects(params, (err, data) => 
      for (let i = 0; i < arrLen; i += 1) 
        let  file = eventsArray[i];
        params.Key = file;
        let fileOut = fs.createWriteStream(`./tmp/$file`);
        let stream = s3.getObject(params).createReadStream().pipe(fileOut);
        console.log(i, arrLen, eventsArray[i]);

        stream.on('close', () => 
          iter += 1;
          console.log(`$i -- file added: $eventsArray[i]`);

          if (iter === arrLen) 
            console.log('-- success! --');
            delete params.Key;
            return;
          
        );
    );
  

输出产生:

--> finding files from s3...
0 9 'harry_test_audio_09.wav'
1 9 'harry_test_audio_08.wav'
2 9 'harry_test_audio_07.wav'
3 9 'harry_test_audio_06.wav'
4 9 'harry_test_audio_05.wav'
5 9 'harry_test_audio_04.wav'
6 9 'harry_test_audio_03.wav'
7 9 'harry_test_audio_02.wav'
8 9 'harry_test_audio_01.wav'
6 -- file added: harry_test_audio_03.wav
8 -- file added: harry_test_audio_01.wav
7 -- file added: harry_test_audio_02.wav
0 -- file added: harry_test_audio_09.wav
5 -- file added: harry_test_audio_04.wav
1 -- file added: harry_test_audio_08.wav
3 -- file added: harry_test_audio_06.wav
4 -- file added: harry_test_audio_05.wav
2 -- file added: harry_test_audio_07.wav
-- success! --

这会产生 9 个名称正确的文件,每个文件只包含第一个文件的内容。

我也尝试使用stream.on('finish' ...stream.on('end' ... 得到类似的结果。

我做错了什么?

【问题讨论】:

您可以使用 s3client 中的“列出对象”方法。我不确定在 node.js 中编写代码的方式。但是在 java 中,有一个方法 listObjects(ListObjectsRequest) 并且在 ListObjectsRequest 中您可以设置存储桶名称和前缀。借助此功能,您可以获得 s3 存储桶中存在的对象列表。之后,您可以获取对象摘要。每个对象摘要都包含该存储桶中的一个键。您可以循环对象摘要并在从该循环派生的每个键上使用 getObject。 最有可能在 javascript 中发生这样的事情时,它必须对闭包做一些事情。我没有调试您的代码,但听起来这就是问题所在。阅读更多相关信息,例如:decembersoft.com/posts/… 感谢@Suyash,但listObjects(); 仅返回s3 中对象的名称和元数据,而我正在尝试将实际文件写入tmp/ 你可能想检查 readstream.pipe 是否阻塞或者它是否与指示 'onData' 、 onEnd 的独立生命周期事件异步...如果是后者,那么你需要将代码更改为异步等待直到每个流/每个 fileOut 在循环内完成 使用 listObjects() 您将获得 ObjectsListings 的对象,您可以从中获得对象摘要列表。每个对象摘要都包含包含 s3 对象键的元数据。因此,通过 getObject() 使用该键和存储桶名称,您可以从 s3 存储桶中检索实际对象。您想从 s3 存储桶中获取所有对象,对吧? 【参考方案1】:

我遇到了同样的问题,这是由于循环中的错误关闭造成的。 解决方案是创建一个未在所有迭代之间共享的 params 副本。

function gets3Objects(eventsArray) 
  console.log('--> finding files from s3...');
  const arrLen = eventsArray.length;
  let iter = 0;

  s3.listObjects(params, (err, data) => 
    for (let i = 0; i < arrLen; i += 1) 
      let  fileParams = 
        Bucket: 'user_events',
        Key: eventsArray[i]
      
      let fileOut = fs.createWriteStream(`./tmp/$file`);
      let stream = s3.getObject(fileParams).createReadStream().pipe(fileOut);
      console.log(i, arrLen, eventsArray[i]);

      stream.on('close', () => 
        iter += 1;
        console.log(`$i -- file added: $eventsArray[i]`);

        if (iter === arrLen) 
          console.log('-- success! --');
          return;
        
      );
    
  );

【讨论】:

以上是关于如何在循环中获取 Amazon S3 对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何从不同于网络的本地文件中读取 InputStream 对象(通过 Amazon S3)?

如何使用 getSignedUrl 操作从 Amazon s3 访问对象

如何在 Amazon Redshift 中定期插入数据?

如何使用预签名的 url 将对象放入 amazon s3?

获取存储在 Amazon S3 上的图像的图像高度和宽度

使用 Amazon s3 boto 库,如何获取已保存密钥的 URL?