2014-07-13 53 views
3

我需要使用到java.util.zip.ZipOutputStream以使用壓縮文件歸檔進行響應。如何在Play 2.1中使用OutputStreams和分塊響應

數據是幾百兆字節未壓縮的,所以我想盡量少存儲它。它來自SQL結果的序列化。

我看到使用OutputStream的例子使用Enumerator.outputStream返回一個分塊結果:

但這些似乎是不明智的,當我閱讀文檔(重點煤礦)

創建一個具有OutputStream的字節枚舉器。

不是說調用寫入操作不會阻塞,所以如果正在輸入的迭代器輸入輸入緩慢,OutputStream不會回退。這意味着它不應該用於大型流,因爲存在 內存不足的風險。

顯然,我不能使用它。或者至少不是沒有修改。


如何創建與OutputStream(在這種情況下,一個壓縮記錄),同時保證它僅部分將被存儲在存儲器中的反應?

我認識InputStream S/OutputStream S和播放的Enumerator/Iteratee範式之間的區別,所以我預計會出現在我需要生成我的源數據(SQL結果的序列化),因此它不」以特定的方式超過下載速度。我不知道它是什麼。

回答

4

一般來說,您不能安全地使用任何OutputStream與枚舉器/ 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 
    } 
} 

如果你需要的是壓縮,看看在play.filters.gzip.Gzip提供的Enumeratee實例和play.filters.gzip.GzipFilter過濾器。

+0

是的,我需要一個zip存檔(幾個文件)。謝謝。 –

0

OutputStream的唯一背壓機制是堵塞螺紋。所以不管怎麼樣,都必須有一個能夠被阻止的線程。

一種方法是使用管道流。

import java.io.OutputStream 
import java.io.PipedInputStream 
import java.io.PipedOutputStream 
import play.api.libs.iteratee.Enumerator 
import scala.concurrent.ExecutorContext 

def outputStream2(a: OutputStream => Unit, bufferSize: Int) 
    (implicit ec1: ExecutionContext, ec2: ExecutionContext) = { 
    val outputStream = new PipedOutputStream 
    Future(a(outputStream))(ec1) 
    val inputStream = new PipedInputStream(pipedOutputStream, bufferSize) 
    Enumerator.fromStream(inputStream)(ec2) 
} 

由於操作處於阻塞狀態,因此必須注意防止死鎖。

要麼使用兩個不同的線程池,要麼使用緩存(無界)線程池。