但該方法實現的方式是把檔案讀取成一個 byte 陣列,再丟給 Response 去回傳。
這會產生一個明顯的問題:這種作法要把整個檔案全部放進記憶體後才能產出,但如果檔案是 10GB 的超大檔案怎麼辦?
因此這次嘗試尋找在 JAX-RS 環境要怎麼辦到以 Stream 來吐檔案下載。
相關的連結可以參考 [2-3] 的討論~主要關鍵是利用 javax.ws.rs.core.StreamingOutput 這個類別。
範例如下:
@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
沒有留言:
張貼留言