我正在使用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
?
答案 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()