通过Akka HTTP或Play从S3流式下载多个文件作为zip

时间:2019-06-30 01:36:40

标签: amazon-web-services playframework akka-stream akka-http alpakka

我有一个S3结构,这是Spark作业的结果,它可以写入分区的CSV文件,如下所示。

bucketA
  output
    cleaned-data1
      part000....csv
      part001....csv
      part002....csv
    cleaned-data2
      .....

我需要的是能够有一个指向输出文件名的Akka HTTP端点,以将所有部分下载为zip文件:https://..../download/cleaned-data1

调用此端点时,理想情况下,我想:

  1. 打开从服务器到客户端浏览器的zip流

  2. 打开零件文件并将字节流直接压缩到zip流中,直接发送给客户端,而无需在服务器上进行任何缓冲以避免内存问题

所有部分的总大小最多可以压缩到30GB。

是否可以通过Akka Stream,Akka HTTP或Play做到这一点?我可以利用Alpakka图书馆吗?

根据拉蒙的答案编辑的临时文件:

  def bucketNameToFileContents(bucket : String) : Source[ByteString, _] =
    bucketNameToKeySource(bucket)
      .map(key => S3.download(bucket, key))
      .map(x => x.map(y => y.fold(Source.empty[ByteString])(_._1)))
      .flatMapConcat(identity)
      .flatMapConcat(identity)

1 个答案:

答案 0 :(得分:0)

第一步是创建akkaSource of the bucket contents

type Key = String

def bucketNameToKeySource(bucket : String) : Source[Key, _] = 
  S3.listBucket(bucket, None)
    .map(_.key)

现在可以将其与S3 download capabilitiesflatMapConcat组合:

def bucketNameToFileContents(bucket : String) : Source[ByteString, _] = 
  bucketNameToKeySource(bucket)
    .map(key => S3.download(bucket, key))
    .map(_.getOrElse(Source.empty[ByteString])
    .flatMapConcat(identity)

此功能现在可以合并到您的Route中。该问题要求“从服务器到客户端打开一个zip流”,因此使用encodeRespose

def bucketNameToRoute(parentBucketName : String) : Route = 
  encodeResponse {
    path ("download" / Segment) { childBucketName =>

      val bucketName = parentBucketName + "/" + childBucketName

      val byteStrSource = bucketNameToFileContents(bucketName)

      complete(OK -> byteStrSource)
    } 
  }