首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java ZIP 壓縮實戰:遞迴壓縮目錄與檔案的完整範例

     編輯:Java 程式設計入門

專案常需將資料夾打包成 ZIP 供下載或備份。Java java.util.zip 套件提供零依賴的壓縮能力,核心類別為 ZipOutputStream。本文提供一個可直接用於生產環境的遞迴壓縮工具類,支援多層目錄、空資料夾保留、大檔案分塊寫入,並妥善處理資源關閉與異常。

一、核心 API 速覽

  • ZipOutputStream:輸出 ZIP 資料流,putNextEntry(ZipEntry) 開始新條目。
  • ZipEntry:代表 ZIP 內單一檔案/目錄條目,名稱含相對路徑。
  • FileInputStream:讀取來源檔案位元組。
  • 緩衝區建議 8192 bytes(8 KB),平衡記憶體與 I/O 效能。

二、完整可執行程式碼

package com.example.util;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public final class ZipUtil {

    private static final int BUFFER_SIZE = 8192;

    private ZipUtil() {} // 工具類禁止實例化

    /**
     * 將來源檔案或目錄壓縮為 ZIP
     * @param srcPath  來源路徑(檔案或資料夾)
     * @param zipPath  目標 ZIP 檔案路徑
     * @throws IOException 壓縮過程發生 I/O 錯誤
     */
    public static void compress(String srcPath, String zipPath) throws IOException {
        File srcFile = new File(srcPath);
        if (!srcFile.exists()) {
            throw new FileNotFoundException("來源不存在:" + srcPath);
        }

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipPath))) {
            // 以來源檔名/目錄名作為 ZIP 內部根條目前綴
            String rootName = srcFile.getName();
            compressRecursive(srcFile, zos, rootName);
        }
        System.out.println("壓縮完成:" + zipPath);
    }

    private static void compressRecursive(File srcFile, ZipOutputStream zos, String entryName) throws IOException {
        if (srcFile.isFile()) {
            // 檔案:建立條目、分塊寫入
            zos.putNextEntry(new ZipEntry(entryName));
            try (FileInputStream fis = new FileInputStream(srcFile)) {
                byte[] buffer = new byte[BUFFER_SIZE];
                int len;
                while ((len = fis.read(buffer)) > 0) {
                    zos.write(buffer, 0, len);
                }
            }
            zos.closeEntry();
        } else if (srcFile.isDirectory()) {
            // 目錄:建立目錄條目(以 / 結尾),遞迴處理子項
            if (!entryName.endsWith("/")) entryName += "/";
            zos.putNextEntry(new ZipEntry(entryName));
            zos.closeEntry();

            File[] children = srcFile.listFiles();
            if (children != null) {
                for (File child : children) {
                    compressRecursive(child, zos, entryName + child.getName());
                }
            }
        }
    }

    // 測試主程式
    public static void main(String[] args) {
        try {
            compress("d:/chat", "d:/chat01.zip");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

三、關鍵細節解析

  1. try-with-resources:JDK 7+ 自動關閉 ZipOutputStream 與 FileInputStream,杜絕資源洩漏。
  2. 目錄條目以 '/' 結尾:ZIP 規範中目錄需以斜線結尾,否則解壓工具可能視為檔案。
  3. 空資料夾保留:listFiles() 回傳空陣列時,上層已建立目錄條目,空資料夾自然保留。
  4. 大檔案分塊:8 KB 緩衝區避免 OutOfMemoryError,且不頻繁觸發 GC。
  5. 異常透傳:拋出 IOException 讓上層決定重試或記錄,不吞噬錯誤。

四、常見擴展需求

  • 排除特定檔案:在遞迴前加 if (child.getName().matches(excludeRegex)) continue;。
  • 壓縮等級控制:zos.setLevel(Deflater.BEST_COMPRESSION) 或 BEST_SPEED。
  • 進度回呼:新增 ProgressListener 介面,寫入位元組時回報進度。
  • 並行壓縮:大量獨立檔案可用 ForkJoinPool 平行壓縮再合併(需臨時檔)。

五、總結

純 JDK 實現 ZIP 壓縮無需第三方庫,掌握 ZipOutputStream 遞迴寫入模式,即可輕鬆應對目錄打包、日誌歸檔、檔案下載等場景。記住「資源自動關閉、目錄條目加斜線、緩衝區適中」三要訣,程式碼既健壯又高效。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved