使用zipoutputstream使用Play发送文件

时间:2017-09-05 01:02:56

标签: scala playframework-2.0 akka akka-stream

我正在为我的磁盘上可能存在的文件提供下载功能。这是在播放/斯卡拉。我有以下下载方法,给我文件。但我想使用ZipOutputstream并发送文件。我不想先在磁盘上压缩文件,然后再进行压缩。我不知道如何实现它。此外,在这种情况下,长度参数是什么样的?

def downloadLocalBackup() = Action  {
    var pathOfFile = "/opt/mycompany/backups/mydir/backup"
    val file = new java.io.File(pathOfFile)
    val path: java.nio.file.Path = file.toPath
    val source: Source[ByteString, _] = FileIO.fromPath(path)

    Ok.sendEntity(HttpEntity.Streamed(source,None, Some("file"))).withHeaders("Content-Disposition"->s"attachment; filename=backup")
}

编辑我的帖子并添加我写的代码,但我不高兴我必须将zip文件读入zip流。我认为这没有优化?

 def downloadLocalBackup2() = Action {
    var pathOfFile = "/opt/mycompany/backups/backupdir/backup"
    val file = new java.io.File(pathOfFile)
    val path: java.nio.file.Path = file.toPath


val enumerator = Enumerator.outputStream { os =>
  val zipStream = new ZipOutputStream(os)
  zipStream.putNextEntry(new ZipEntry("backup2"))
  val is = new BufferedInputStream(new FileInputStream(pathOfFile))
  val buf = new Array[Byte](1024)
  var len = is.read(buf)
  while (len >= 0) {
    zipStream.write(buf, 0 ,len)
    len = is.read(buf)
  }
  is.close
  zipStream.close()
}

val kk = Ok.sendEntity(HttpEntity.Streamed(Source.fromPublisher(Streams.enumeratorToPublisher(enumerator)).map(x=>{val kk = Writeable.wByteArray.transform(x);kk}),
  None, Some("application/zip"))
).withHeaders("Content-Disposition" -> s"attachment; filename=backupfile.zip")
kk

}

2 个答案:

答案 0 :(得分:0)

在这种情况下,您可以使用GZIPOutputStream:

import java.io.ByteArrayOutputStream
import java.util.zip.GZIPOutputStream

val txt = "text to zip"
val arrOutputStream = new ByteArrayOutputStream()
val zipOutputStream = new GZIPOutputStream(arrOutputStream)
zipOutputStream.write(txt.getBytes)
zipOutputStream.close()

val result: Array[Byte] = arrOutputStream.toByteArray

答案 1 :(得分:0)

您可以使用CompressionZipOutputStream的流进行gzip压缩,而不是使用ByteString

val source: Source[ByteString, _] =
  FileIO.fromPath(path)
        .via(Compression.gzip)

您需要一个能够使用相应的Compression.gunzip()来处理压缩数据流的消费者。

对于contentLength,明确提供它而不是使用None(如果将其保留为None,Play会将整个文件加载到内存中以计算长度):< / p>

val contentLength = Some(file.length)

Ok.sendEntity(HttpEntity.Streamed(source, contentLength, Some("file"))).withHeaders("Content-Disposition" -> s"attachment; filename=backup")