但該方法實現的方式是把檔案讀取成一個 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
沒有留言:
張貼留言