核心壓縮方法
// 參數:zipPath 目的壓縮檔路徑、srcPath 來源目錄、out JSP 輸出
void zip(String zipPath, String srcPath, javax.servlet.jsp.JspWriter out) throws Exception {
FileOutputStream output = null;
ZipOutputStream zipOutput = null;
try {
output = new FileOutputStream(zipPath);
zipOutput = new ZipOutputStream(output);
zipEntry(zipOutput, srcPath, srcPath, zipPath);
out.print("zip ok: " + zipPath);
} catch (Exception e) {
out.print("file zip error: " + e.getMessage());
} finally {
if (zipOutput != null) zipOutput.close();
}
}
// 遞迴處理目錄項目
void zipEntry(ZipOutputStream zipOs, String initPath, String filePath, String zipPath) throws Exception {
String entryName = filePath;
File f = new File(filePath);
if (f.isDirectory()) {
String[] files = f.list();
for (int i = 0; i < files.length; i++) {
zipEntry(zipOs, initPath, filePath + File.separator + files[i], zipPath);
}
return;
}
// 計算相對路徑作為 ZIP 內部路徑
String chPh = initPath.substring(initPath.lastIndexOf("/") + 1);
int idx = initPath.lastIndexOf(chPh);
if (idx != -1) entryName = filePath.substring(idx);
ZipEntry entry = new ZipEntry(entryName);
File ff = new File(filePath);
if (ff.getAbsolutePath().equals(zipPath)) return; // 排除壓縮檔本身
entry.setSize(ff.length());
entry.setTime(ff.lastModified());
entry.setCrc(0); // 稍後計算
CRC32 crc = new CRC32();
crc.reset();
zipOs.putNextEntry(entry);
byte[] buffer = new byte[2048];
FileInputStream input = null;
try {
input = new FileInputStream(filePath);
int len;
while ((len = input.read(buffer)) != -1) {
zipOs.write(buffer, 0, len);
crc.update(buffer, 0, len);
}
} finally {
if (input != null) input.close();
}
entry.setCrc(crc.getValue());
}
呼叫範例
<%
String srcDir = application.getRealPath("/data/export");
String zipFile = application.getRealPath("/downloads/export_" + System.currentTimeMillis() + ".zip");
zip(zipFile, srcDir, out);
%>
關鍵技術點
| 項目 | 處理方式 |
| 編碼問題 | 檔名含中文需設定 ZipEntry 編碼或使用 Apache Commons Compress |
| 大檔案 | 串流式讀寫避免記憶體溢出,緩衝區 2048 bytes |
| 空目錄 | 遞迴處理,空目錄不產生 Entry (ZIP 標準) |
| 排除自身 | 判斷 ff.getAbsolutePath().equals(zipPath) 避免壓縮到自己 |
| CRC32 校驗 | 寫入時同步計算,最後設定 entry.setCrc() |
生產環境建議
- 使用 Apache Commons Compress 或 Apache Ant Zip 成熟庫替代手寫
- 非同步處理:提交壓縮任務至執行緒池,前端輪詢狀態
- 加入進度回呼、取消機制、錯誤重試
- 壓縮完成提供下載連結或郵件通知
- 定期清理暫存壓縮檔避免磁碟佔滿
Linux/Windows 跨平台測試
程式碼使用 File.separator 自動適配路徑分隔符,已在 Linux 與 Windows 環境測試通過。
- 上一篇文章: Tomcat 6 EL 運算式三元運算子解析錯誤與解決方案
- 下一篇文章: JSP 表單資料儲存兩種通用方法比較
Copyright ©
程式碼之家 All Rights Reserved