但該方法實現的方式是把檔案讀取成一個 byte 陣列,再丟給 Response 去回傳。
這會產生一個明顯的問題:這種作法要把整個檔案全部放進記憶體後才能產出,但如果檔案是 10GB 的超大檔案怎麼辦?
因此這次嘗試尋找在 JAX-RS 環境要怎麼辦到以 Stream 來吐檔案下載。
相關的連結可以參考 [2-3] 的討論~主要關鍵是利用 javax.ws.rs.core.StreamingOutput 這個類別。
範例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
@Path ( "/file" ) @Provider public class FileInterface { @GET @Path ( "/get" ) @Produces (MediaType.APPLICATION_OCTET_STREAM) public Response fileDownload () throws IOException { System.out.println( "REST /file/get is connected." ); File file = new File( "test.zip" ); ChunkStreamingOutput stream = new ChunkStreamingOutput( new FileInputStream(file)); return Response .ok(stream, MediaType.APPLICATION_OCTET_STREAM_TYPE) .header( "content-disposition" , "attachment; filename=" + file.getName()) .build(); } private class ChunkStreamingOutput implements StreamingOutput { private InputStream is = null ; public ChunkStreamingOutput (InputStream stream) { this .is = stream; } @Override public void write(OutputStream output) throws IOException, WebApplicationException { try { byte [] buffer = new byte [ 1024 ]; int len = 0 ; while ((len = is.read(buffer)) > - 1 ) { output.write(buffer, 0 , len); output.flush(); } } finally { if (is != null ) is.close(); if (output != null ) output.close(); } } } } |
特別的地方大概是在 27 行處的 write(OutputStream output)~
輸入的 OutputStream 應該可以看做是 Response 物件用來吐出 Stream 的物件
因此要輸出的檔案的 Stream 都要寫到那個 OutputStream 裡。
這裡我的作法是自己自訂一個 StreamingOutput 的類別,然後允許輸入一個 InputStream
這樣可以允許我需要時,可以用 FileInputStream、也可以用別種 InputStream 的實作類別來提供 Stream 的來源。
參考資料:
1、在 JAX-RS 實現上傳檔案及下載檔案
2、Input and Output binary streams using JERSEY?
3、jersey Example of using StreamingOutput as Response entity
沒有留言:
張貼留言