java.util.zip 基礎用法JDK 內建 ZipOutputStream / ZipInputStream 可完成基本壓縮解壓,核心流程:
putNextEntry → 寫入位元組 → closeEntrygetNextEntry 迴圈 → 判斷目錄/檔案 → 建立父目錄 → 寫入檔案完整可運行範例(含緩衝區大小可調):
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 或產生亂碼檔名。
引入 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
ZipOutputStream 建構子可傳入 Charset(JDK 7),但僅影響項目註解,不影響檔名編碼,實務上仍建議用 AntZip。
readAllBytes,採用固定緩衝區(如 8KB)分塊讀寫。ZipEntry 名稱以 / 結尾即視為目錄。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 並明確指定編碼。結合緩衝區調優、安全檢查與平行化,即可構建生產級壓縮工具。