如何在循环中获取 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 对象?的主要内容,如果未能解决你的问题,请参考以下文章