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

Java ZIP 壓縮解壓工具類:標準庫實現目錄遞歸、校驗和流式處理

     編輯:Java 程式設計入門

工具類 ZipUtil 核心功能

  • 目錄遞歸壓縮,保留相對路徑
  • Adler32 校驗和完整性驗證
  • 緩衝流提升效能(10KB 緩衝區)
  • 解壓自動建立目錄、防止路徑遍歷

壓縮 zip(sourceDir, destDir)

public static boolean zip(String sourceDir, String destDir) {
    File src = new File(sourceDir);
    if (!src.exists() || !src.isDirectory()) return false;

    File zipFile = new File(destDir, src.getName() + ".zip");
    if (zipFile.exists()) return false;

    try (FileOutputStream fos = new FileOutputStream(zipFile);
         CheckedOutputStream cos = new CheckedOutputStream(fos, new Adler32());
         ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(cos))) {

        zos.setMethod(ZipOutputStream.DEFLATED);
        compress(src, zos, src.getName());
        return true;
    } catch (IOException e) { e.printStackTrace(); return false; }
}

private static void compress(File file, ZipOutputStream zos, String rootName) throws IOException {
    if (file.isFile()) {
        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream bis = new BufferedInputStream(fis, BUFFER)) {
            String entryName = file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(rootName));
            zos.putNextEntry(new ZipEntry(entryName));
            byte[] buf = new byte[BUFFER];
            int len;
            while ((len = bis.read(buf)) > 0) zos.write(buf, 0, len);
            zos.closeEntry();
        }
    } else if (file.isDirectory()) {
        for (File f : file.listFiles()) compress(f, zos, rootName);
    }
}

解壓 unzip(zipFile, destDir)

public static boolean unzip(File zipFile, String destDir) {
    if (!zipFile.exists()) return false;
    File target = new File(destDir);
    if (!target.exists()) target.mkdirs();

    String rootName = zipFile.getName().replace(".zip", "");
    try (FileInputStream fis = new FileInputStream(zipFile);
         CheckedInputStream cis = new CheckedInputStream(fis, new Adler32());
         ZipInputStream zis = new ZipInputStream(new BufferedInputStream(cis))) {

        ZipEntry entry;
        while ((entry = zis.getNextEntry()) != null) {
            String entryName = entry.getName();
            int idx = entryName.indexOf(rootName);
            if (idx == -1) continue; // 防惡意路徑
            String outPath = destDir + "/" + entryName.substring(idx);
            File outFile = new File(outPath);

            if (entry.isDirectory()) {
                outFile.mkdirs();
            } else {
                outFile.getParentFile().mkdirs();
                try (FileOutputStream fos = new FileOutputStream(outFile);
                     BufferedOutputStream bos = new BufferedOutputStream(fos, BUFFER)) {
                    byte[] buf = new byte[BUFFER];
                    int len;
                    while ((len = zis.read(buf)) > 0) bos.write(buf, 0, len);
                }
            }
            zis.closeEntry();
        }
        return true;
    } catch (IOException e) { e.printStackTrace(); return false; }
}

替代實現 ZipToFile(Apache 風格)

  • 使用 ZipFile 而非 ZipInputStream,支援隨機存取
  • 更完善的目錄條目處理(entry.isDirectory())
  • 異常轉 RuntimeException 向上拋出

效能與安全建議

場景建議
大檔案 (>100MB)啟用 Zip64Mode.AsNeeded(Java 7+)
高併發線程池分片壓縮,或使用 Zip4j 並行壓縮
加密需求Zip4j 支援 AES-256,標準庫不支援加密
路徑遍歷防護解壓時規範化路徑,確保在目標目錄下
記憶體控制流式讀寫,避免 byte[] 裝載整個檔案

現代 API:Java NIO.2 FileSystem

// JDK 7+ ZIP 檔案系統提供者
try (FileSystem fs = FileSystems.newFileSystem(zipPath, Map.of("create", "true"))) {
    Files.copy(srcPath, fs.getPath("/target.txt"), StandardCopyOption.REPLACE_EXISTING);
}

將 ZIP 視為檔案系統,支援 Files.walk、Files.copy 等標準 NIO 操作,代碼極簡潔。

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