Я сейчас пытаюсь собрать и отправить zip-архив с Play framework 2.7. Я хотел бы собрать архив на лету, чтобы не использовать хранилище (или заполнять оперативную память).
Я нашел хорошее решение с Enumerator , но с текущей версией Play Framework мне нужно собратьAkka Source
.
Моя текущая попытка:
val streamContent = StreamConverters
.asOutputStream()
.mapMaterializedValue( ZipUtil.zip(ds.files) )
Ok.chunked(streamContent)
.as("application/zip")
.withHeaders( CONTENT_DISPOSITION -> "attachment;" )
, где ZipUtil.zip(...)
определяется как:
def zip(files: Iterable[Path]): OutputStream => Unit = { os =>
val zipOut = new ZipOutputStream(os)
val bytesBuffer = ByteBuffer.allocate(8192)
files.foreach { f =>
val fileName = f.getFileName.toString
val ze = new ZipEntry(fileName)
zipOut.putNextEntry(ze)
val channel = Files.newByteChannel(f, StandardOpenOption.READ)
bytesBuffer.clear()
var numBytes = channel.read(bytesBuffer)
while (numBytes != -1) {
val bytes = bytesBuffer.array()
zipOut.write(bytes, 0, numBytes)
bytesBuffer.clear()
numBytes = channel.read(bytesBuffer)
}
channel.close()
}
zipOut.close()
}
Однако, похоже, что это тупик. Если я добавлю расширенное ведение журнала, оно застревает при вызове putNextEntry
. Конечно, я тестировал метод zip(...)
вне механизма обработки потоков akka, и он хорошо работал.
Я также пытался использовать StreamConverters.fromInputStream
и использовать потоковые потоки ввода-вывода для подключения ZipOutputStream
к Source
1022 * безуспешно.