標準 JDK java.util.zip 對中文檔名支援較差,採用 Apache Ant 的 org.apache.tools.zip 可完美解決編碼問題,並支援 ZipEntry 目錄項目。
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.10.14</version>
</dependency>
import java.io.*;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
public class CompressedFileUtil {
/** 預設建構子 */
public CompressedFileUtil() {}
/**
* 壓縮指定檔案或目錄為 ZIP
* @param resourcesPath 來源路徑(檔案或資料夾)
* @param targetPath 目標壓縮檔存放目錄
* @throws Exception
*/
public void compressedFile(String resourcesPath, String targetPath) throws Exception {
File resourcesFile = new File(resourcesPath);
File targetDir = new File(targetPath);
if (!targetDir.exists()) targetDir.mkdirs();
String zipName = resourcesFile.getName() + ".zip";
FileOutputStream fos = new FileOutputStream(new File(targetDir, zipName));
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos));
createCompressedFile(zos, resourcesFile, "");
zos.close();
}
/**
* 遞歸建立壓縮項目
*/
private void createCompressedFile(ZipOutputStream out, File file, String dir) throws Exception {
if (file.isDirectory()) {
File[] files = file.listFiles();
// 加入目錄項目(以 / 結尾)
out.putNextEntry(new ZipEntry(dir + "/"));
dir = dir.isEmpty() ? "" : dir + "/";
for (File f : files) {
createCompressedFile(out, f, dir + f.getName());
}
} else {
// 檔案項目
FileInputStream fis = new FileInputStream(file);
out.putNextEntry(new ZipEntry(dir));
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
fis.close();
}
}
/** 測試主程式 */
public static void main(String[] args) {
CompressedFileUtil util = new CompressedFileUtil();
try {
util.compressedFile("G:\\zip", "F:\\zip");
System.out.println("壓縮檔案已生成...");
} catch (Exception e) {
System.out.println("壓縮失敗...");
e.printStackTrace();
}
}
}
ZipEntry(name + "/") 明確標示目錄,解壓時可正確建立資料夾結構。dir 累加相對路徑,確保壓縮包內層級正確。BufferedOutputStream 包裝 FileOutputStream,再包裝 ZipOutputStream,提升寫入效能。finally 區塊或 try-with-resources 確保流關閉(JDK 7+ 建議改用 try-with-resources)。zos.setLevel(Deflater.BEST_COMPRESSION)| 問題 | 原因 | 解決 |
|---|---|---|
| 中文檔名解壓亂碼 | JDK 預設 ZIP 使用 UTF-8,Windows 預設 GBK | 使用 Apache Ant Zip 並設定 encoding:zos.setEncoding("GBK") 或 UTF-8 |
| 空目錄未壓縮 | listFiles() 回傳 null 或空陣列 | 目錄項目已在遞歸入口建立,空目錄會生成對應 Entry |
| 大檔案記憶體溢位 | 一次性讀入整個檔案 | 採用 1KB~8KB 緩衝區分塊讀寫(本範例已採用) |