Web 下載多檔案打包、報表匯出、日志歸檔等場景,需將多個檔案壓縮為 ZIP 並以 ByteArrayOutputStream 形式回傳,後續可直接寫入 HTTP 響應或進行 MD5 校驗。
fileToZip 方法public ByteArrayOutputStream fileToZip(List<String> fileList, String zipName, String tempFilePath) {
byte[] buffer = new byte[1024];
ZipOutputStream out = null;
try {
// 1. 建立臨時 ZIP 檔
out = new ZipOutputStream(new FileOutputStream(tempFilePath + zipName + ".zip"));
List<File> files = new ArrayList<>();
for (String path : fileList) {
files.add(new File(path));
}
// 2. 逐個寫入 ZIP 條目
for (File file : files) {
try (FileInputStream fis = new FileInputStream(file)) {
out.putNextEntry(new ZipEntry(file.getName()));
int len;
while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
out.closeEntry();
}
}
out.close();
// 3. 讀取 ZIP 至記憶體流
File zipFile = new File(tempFilePath + zipName + ".zip");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (FileInputStream fis = new FileInputStream(zipFile);
BufferedInputStream bis = new BufferedInputStream(fis)) {
int b;
while ((b = bis.read()) != -1) {
baos.write(b);
}
}
return baos;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (out != null) try { out.close(); } catch (IOException ignored) {}
}
}
// 參數準備
String tempPath = "C:/temp/";
List<String> files = Arrays.asList(
tempPath + "file1.txt",
tempPath + "file2.png",
tempPath + "file3.xls"
);
String zipName = "fileData";
// 取得壓縮流
ByteArrayOutputStream out = fileToZip(files, zipName, tempPath);
byte[] data = out.toByteArray();
// 寫入 HTTP 響應
response.reset();
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition",
"attachment;filename=" + new String("dataFile.zip".getBytes("GBK"), "ISO8859-1"));
response.addHeader("Content-Length", String.valueOf(data.length));
try (BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
bos.write(data);
bos.flush();
}
| 環節 | 注意點 |
|---|---|
| 編碼處理 | 中文檔名需 GBK → ISO8859-1 轉碼,避免下載亂碼 |
| 資源釋放 | 所有 Stream 必須在 finally 或 try-with-resources 中關閉 |
| 大檔案 | 若總大小超過記憶體,建議改用 ServletOutputStream 邊壓縮邊輸出 |
| 臨時檔清理 | 業務結束後應刪除 tempFilePath 下的臨時 ZIP |
File.listFiles(),保留相對路徑Zip4j 庫實現 AES 加密ForkJoinPool 分片處理