首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Servlet實現多文件打包下載:使用ZipOutputStream壓縮輸出流

     編輯:程式設計綜合問答

核心思路

**零臨時文件**,直接將多個文件流式壓縮寫入 `HttpServletResponse` 的輸出流,利用 `ZipOutputStream` 邊讀邊壓邊輸出。

完整 Servlet 代碼


@WebServlet("/batchDownload")
public class BatchDownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 獲取前端傳來的文件 ID 列表 (如 "1,2,3")
        String[] fileIds = req.getParameterValues("fileId");
        if (fileIds == null || fileIds.length == 0) {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "未選擇文件");
            return;
        }

        // 2. 設置響應頭:ZIP 下載
        String zipName = "download_" + System.currentTimeMillis() + ".zip";
        resp.setContentType("application/zip");
        resp.setHeader("Content-Disposition", "attachment; filename=\"" + zipName + "\"");

        // 3. 核心:ZipOutputStream 包裝 response.getOutputStream()
        try (ZipOutputStream zos = new ZipOutputStream(resp.getOutputStream())) {
            for (String id : fileIds) {
                // 3.1 根據 ID 獲取文件元信息 (路徑、名稱) - 此處模擬
                File file = fileService.getFileById(id); // 假設返回 File 對象
                if (file == null || !file.exists()) continue;

                // 3.2 放入 ZIP 條目
                ZipEntry entry = new ZipEntry(file.getName());
                zos.putNextEntry(entry);

                // 3.3 流式複製文件內容到 ZIP (緩衝區 8KB)
                try (FileInputStream fis = new FileInputStream(file)) {
                    byte[] buffer = new byte[8192];
                    int len;
                    while ((len = fis.read(buffer)) > 0) {
                        zos.write(buffer, 0, len);
                    }
                }
                zos.closeEntry(); // 關閉當前條目
            }
            zos.finish(); // 完成 ZIP 寫入 (寫入中央目錄)
        } // try-with-resources 自動關閉 zos 及底層 outputStream
    }
}

關鍵點詳解

前端調用示例


// 勾選文件後
const ids = [...document.querySelectorAll('input[name="fileId"]:checked')].map(cb => cb.value);
if (ids.length) {
    window.location.href = `/batchDownload?fileId=${ids.join('&fileId=')}`;
}

擴展:大文件/超多文件優化

  • **異步生成 + 轮詢下載**:後台線程生成 ZIP 存臨時目錄,返回任務 ID,前端輪詢狀態,完成提供下載鏈接。
  • **斷點續傳**:配合 `Range` 請求頭,支持大 ZIP 分片下載。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
環節說明
`ZipOutputStream`直接寫入 HTTP 響應流,無需在服務器磁盤生成臨時 ZIP 文件,節省 IO、空間、併發風險。
`putNextEntry` / `closeEntry`每個文件一個 Entry,必須成對調用,否則 ZIP 結構損壞。
緩衝區 `byte[8192]`避免大文件一次性讀入內存 OOM,流式分塊傳輸。
`try-with-resources`JDK 7+ 語法,保證 `zos`、`fis` 異常時也能正確關閉,釋放文件句柄。
文件名編碼中文文件名需 `URLEncoder.encode(name, "UTF-8")` 處理 `Content-Disposition`,防止下載亂碼。