GZIP 是廣泛使用的無損壓縮格式。本文提供生產級 GZipUtils 工具類,支援 byte[]、File、InputStream/OutputStream、String 路徑四種輸入源的壓縮與解壓,採用流式處理避免大文件內存溢出,完善異常處理與資源釋放。
public abstract class GZipUtils {
public static final int BUFFER = 1024; // 1KB 緩衝區
public static final String EXT = ".gz"; // 壓縮文件後綴
// 壓縮入口:byte[]、File、InputStream、String 路徑
// 解壓入口:byte[]、File、InputStream、String 路徑
// 所有方法最終委託給核心流式處理方法
}
使用 GZIPOutputStream 包裝輸出流,分塊讀取輸入流寫入,最後調用 finish() 確保壓縮數據刷新。
public static void compress(InputStream is, OutputStream os) throws Exception {
try (GZIPOutputStream gos = new GZIPOutputStream(os)) {
byte[] data = new byte[BUFFER];
int count;
while ((count = is.read(data, 0, BUFFER)) != -1) {
gos.write(data, 0, count);
}
gos.finish(); // 關鍵:寫入 GZIP 尾部標記
gos.flush();
}
}
使用 GZIPInputStream 包裝輸入流,透明解壓讀取,寫入輸出流。
public static void decompress(InputStream is, OutputStream os) throws Exception {
try (GZIPInputStream gis = new GZIPInputStream(is)) {
byte[] data = new byte[BUFFER];
int count;
while ((count = gis.read(data, 0, BUFFER)) != -1) {
os.write(data, 0, count);
}
}
}
| 場景 | 壓縮方法 | 解壓方法 | 特點 |
|---|---|---|---|
| 內存數據 | compress(byte[]) → byte[] | decompress(byte[]) → byte[] | ByteArrayInputStream/OutputStream 內存流 |
| 文件對象 | compress(File, boolean delete) | decompress(File, boolean delete) | 自動生成 .gz 後綴、可選刪除源文件 |
| 流處理 | compress(InputStream, OutputStream) | decompress(InputStream, OutputStream) | 核心邏輯、最大靈活性、管道流適用 |
| 文件路徑 | compress(String, boolean delete) | decompress(String, boolean delete) | 路徑字符串便捷入口、內部轉 File |
public static void compress(File file, boolean delete) throws Exception {
try (FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file.getPath() + EXT)) {
compress(fis, fos); // 委託核心流式方法
}
if (delete) file.delete();
}
public static void decompress(File file, boolean delete) throws Exception {
String targetPath = file.getPath().replace(EXT, "");
try (FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(targetPath)) {
decompress(fis, fos);
}
if (delete) file.delete();
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 解壓後文件損壞/大小為0 | 未調用 gos.finish() 或流未正確關閉 | 確保 try-with-resources 包含 finish() 或顯式調用 |
| GZIPInputStream 讀取拋出 EOFException | 輸入非標準 GZIP 格式、文件截斷、未壓縮文件誤作解壓 | 驗證文件魔數 (0x1f 0x8b)、捕獲異常友好提示 |
| 壓縮大文件 OOM | 誤將整文件讀入內存 (byte[]) | 堅持流式分塊讀寫、避免 toByteArray() |
| 中文文件名亂碼 | GZIP 不存儲文件名元數據 | 應用層維護文件名映射、或使用 ZIP 格式 |