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

Java ZIP 壓縮與解壓實戰:標準庫、中文亂碼避坑與 AntZip 替代方案

     編輯:Java 相關知識

標準 java.util.zip 基礎用法

JDK 內建 ZipOutputStream / ZipInputStream 可完成基本壓縮解壓,核心流程:

  • 壓縮:遞迴遍歷目錄 → putNextEntry → 寫入位元組 → closeEntry
  • 解壓:getNextEntry 迴圈 → 判斷目錄/檔案 → 建立父目錄 → 寫入檔案

完整可運行範例(含緩衝區大小可調):

public class Zip {
    private ZipOutputStream zipOut;
    private ZipInputStream zipIn;
    private byte[] buf;
    // 建構子、setBufSize()...

    public void doZip(String dir) throws IOException {
        File zipDir = new File(dir);
        String zipName = zipDir.getName() + ".zip";
        zipOut = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipName)));
        handleDir(zipDir, zipOut);
        zipOut.close();
    }

    private void handleDir(File dir, ZipOutputStream out) throws IOException {
        File[] files = dir.listFiles();
        if (files.length == 0) {
            out.putNextEntry(new ZipEntry(dir.getPath() + "/"));
            out.closeEntry();
        } else {
            for (File f : files) {
                if (f.isDirectory()) handleDir(f, out);
                else {
                    try (FileInputStream in = new FileInputStream(f)) {
                        out.putNextEntry(new ZipEntry(f.getPath()));
                        int len;
                        while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
                        out.closeEntry();
                    }
                }
            }
        }
    }

    public void unZip(String zipFile) throws IOException {
        zipIn = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
        ZipEntry entry;
        while ((entry = zipIn.getNextEntry()) != null) {
            File outFile = new File(entry.getName());
            if (entry.isDirectory()) outFile.mkdirs();
            else {
                File parent = outFile.getParentFile();
                if (parent != null && !parent.exists()) parent.mkdirs();
                try (FileOutputStream out = new FileOutputStream(outFile)) {
                    int len;
                    while ((len = zipIn.read(buf)) > 0) out.write(buf, 0, len);
                }
            }
            zipIn.closeEntry();
        }
    }
}

中文檔名亂碼根因與兩大解法

根因:java.util.zip 僅支援 UTF-8 編碼讀寫 ZIP 標頭,若原壓縮檔使用 CP950/Big5/GBK 等編碼,解壓時會拋出 IllegalArgumentException 或產生亂碼檔名。

方案一:Apache Ant Zip(推薦)

引入 ant.jar,改用 org.apache.tools.zip.*,支援指定編碼:

<dependency>
  <groupId>org.apache.ant</groupId>
  <artifactId>ant</artifactId>
  <version>1.10.14</version>
</dependency>

// 使用範例
ZipOutputStream out = new ZipOutputStream(new FileOutputStream("out.zip"));
out.setEncoding("Big5"); // 或 UTF-8, GBK...
// 後續操作同標準 API

方案二:JDK 7+ 標準庫參數(有限支援)

ZipOutputStream 建構子可傳入 Charset(JDK 7),但僅影響項目註解,不影響檔名編碼,實務上仍建議用 AntZip。

進階技巧與最佳實務

  • 串流處理大檔:避免一次 readAllBytes,採用固定緩衝區(如 8KB)分塊讀寫。
  • 保留空目錄:ZipEntry 名稱以 / 結尾即視為目錄。
  • 安全解壓:防止 Zip Slip 攻擊,解壓前驗證 entry.getName() 無 ../ 路徑遍歷。
  • 平行壓縮:大量檔案可配合 ForkJoinPool 或 CompletableFuture 並行處理不同目錄。

常見指令列操作封裝

public static void main(String[] args) {
    if (args.length != 2) {
        System.out.println("Usage: java Zip -zip|-unzip ");
        return;
    }
    Zip zip = new Zip(8192);
    try {
        if ("-zip".equals(args[0])) zip.doZip(args[1]);
        else if ("-unzip".equals(args[0])) zip.unZip(args[1]);
    } catch (IOException e) { e.printStackTrace(); }
}

總結

標準庫適合純 ASCII 環境;涉及中文檔名務必改用 Apache Ant Zip 並明確指定編碼。結合緩衝區調優、安全檢查與平行化,即可構建生產級壓縮工具。

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