将AWS S3对象转换为ByteString问题

时间:2018-04-29 14:07:57

标签: scala amazon-s3 akka

我正在使用Akka处理从S3上传文件到Facebook的过程。根据Facebook API文档,文件应该通过小部分上传 - 块。根据文件大小,Facebook会为您提供有关预期在下一个请求中收到的字节偏移量的信息。

首先,我通过Java AWS SDK对S3进行GetObjectRequest,以便接收具有所需字节大小的块:

val objChunkReq = new GetObjectRequest(get.s3ObjId.bucketName, get.s3ObjId.key)
  objChunkReq.setRange(get.fbUploadSession.from, get.fbUploadSession.to)

  Try(s3Client.getObject(objChunkReq)) match {
    case Success(s3ObjChunk) => Right(S3ObjChunk(s3ObjChunk, get.fbUploadSession))
    case Failure(ex) => Left(S3Exception(ex.getMessage))
  }

然后,如果S3响应成功,我可以像使用InputStream一样处理收到的块,然后将其传递给Facebook HTTP请求:

private def inputStreamToArrayByte(is: InputStream) = {
  Try {
    val reads: Int = is.read()
    val byteStringBuilder = ByteString.newBuilder
    while (is.read() != -1) {
      byteStringBuilder.asOutputStream.write(reads)
      is.read()
    }
    is.close()
    byteStringBuilder.result()
  }
}

我遇到的问题是,第一个代码段中的s3ObjChunk大小的字节大小是第二个代码段中生成的ByteString的两倍大。

s3ObjChunk.getObjectMetadata.getContentLength == n

byteStringBuilder.result().length == n / 2

我有两个假设: a)我错误地将InputStream转换为ByteString b)ByteString压缩InputStream

如何正确地将S3对象InputStream转换为ByteString

1 个答案:

答案 0 :(得分:1)

结果输出中n vs n / 2的问题可能是由实施中的错误解释的。

is.read()在循环中被调用两次,并且它的所有返回都没有写入输出流,而只是第一个,存储在val reads中。

实施应该改为:

val byteStringBuilder = ByteString.newBuilder
val output = byteStringBuilder.asOutputStream
try {
  var reads: Int = is.read() // note "var" instead of "val"
  while (reads != -1) {
    output.write(reads)
    reads = is.read()
  }
} finally {
  is.close() // should it be here or closed by the caller?
  // also close "output"
}
byteStringBuilder.result()

或者,另一种方法是使用scala.io.Source稍微更惯用的流读取,例如:

val byteStringBuilder = ByteString.newBuilder
val output = byteStringBuilder.asOutputStream
scala.io.Source.fromInputStream(is).foreach(output.write(_))
byteStringBuilder.result()