ZipUtil 核心功能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[] 裝載整個檔案 |
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 操作,代碼極簡潔。