如何在Play 2.1中使用带有分块响应的OutputStreams

时间:2014-07-13 00:59:26

标签: scala playframework outputstream iterate

我需要使用java.util.zip.ZipOutputStream来回复压缩文件存档。

数据是几百兆字节未压缩,所以我想尽可能少地存储。它来自SQL结果的序列化。

我看到使用OutputStream使用Enumerator.outputStream返回分块结果的示例:

但是当我阅读文档(强调我的)时,这些似乎是不明智的

  

使用OutputStream创建一个字节的枚举器。

     

写入的调用不会阻塞,所以如果被输入的iteratee使用输入的速度很慢,那么   OutputStream不会回推。这意味着它不应该用于大流,因为存在风险   内存不足

显然,我无法使用它。或者至少没有修改。


如何使用OutputStream创建响应(在这种情况下,是一个gzip压缩文件),同时确保只有部分内容存储在内存中?

我认识到InputStream s / OutputStream和Play Enumerator / Iteratee范例之间的区别,所以我希望我需要一种特定的方式生成我的源数据(SQL结果的序列化),使其不超过下载速度。我不知道它是什么。

2 个答案:

答案 0 :(得分:4)

一般情况下,您无法安全地将任何OutputStream与Enumerator / Iteratee框架一起使用,因为OutputStream不支持非阻止回退。但是,如果你可以控制对OutputStream的写作,你可以将这些内容整合起来:

val baos = new ByteArrayOutputStream
val zos = new ZipOutputStream(baos)

val enumerator = Enumerator.generateM {
  Future.successful {
    if (moreDateToWrite) {
      // Write data into zos
      val r = Some(baos.toByteArray)
      baos.reset()
      r
    } else None
  }
}

如果您只需要压缩,请查看Enumerateeplay.filters.gzip.Gzip过滤器中提供的play.filters.gzip.GzipFilter个实例。

答案 1 :(得分:0)

ViewDidLoad()唯一的反压机制是阻塞线程。所以,不管怎样,必须有一个能够被阻止的线程。

一种方法是使用管道流。

Unable to bind: source property source not found IndexedProperty:0 on String[]

由于操作阻塞,您必须注意防止死锁。

使用两个不同的线程池,或使用缓存(无界)线程池。