Преобразование объекта AWS S3 в проблему ByteString - PullRequest
0 голосов
/ 29 апреля 2018

Я работаю над процессом загрузки файлов из S3 в Facebook с помощью Akka. Согласно документации API Facebook, файлы должны загружаться небольшими частями - кусками. В зависимости от размера файла Facebook предоставляет вам информацию о смещении в байтах, которую он ожидает получить в следующем запросе.

Сначала я делаю GetObjectRequest на S3 через Java AWS SDK, чтобы получить чанк с требуемым размером в байтах:

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, чтобы затем передать его в HTTP-запрос Facebook:

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

У меня есть два предположения: а) Я неправильно преобразовываю InputStream в ByteString б) ByteString сжимает InputStream

Как правильно преобразовать объект S3 InputStream в ByteString?

1 Ответ

0 голосов
/ 29 апреля 2018

Проблема с n против 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()
...