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

Java Deflate 壓縮/解壓縮實作指南:Deflater 與 Inflater 完整範例

     編輯:Java 相關知識

前言

在網路傳輸、檔案儲存、快取系統中,資料壓縮能大幅降低頻寬與空間成本。Java 核心套件 java.util.zip 提供基於 DEFLATE 演算法(LZ77 + Huffman 編碼)的 Deflater(壓縮)與 Inflater(解壓縮),無需第三方庫即可使用。本文提供生產級工具類實作與關鍵細節解析。

核心 API 速覽

類別關鍵方法說明
DeflatersetInput(byte[])設定待壓縮資料
finish()標記輸入結束,準備輸出剩餘壓縮資料
deflate(byte[])執行壓縮,回傳寫入位元組數
end()釋放原生資源
InflatersetInput(byte[])設定待解壓資料
inflate(byte[])執行解壓,回傳寫入位元組數
finished()判斷解壓是否完成
end()釋放原生資源

完整工具類實作

import java.io.*;
import java.util.zip.*;
import org.apache.commons.codec.binary.Base64; // 需 commons-codec 依賴

public class DeflateUtils {

    /** 壓縮位元組陣列 */
    public static byte[] compress(byte[] input) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            Deflater deflater = new Deflater();
            deflater.setInput(input);
            deflater.finish(); // 關鍵:告知無後續輸入
            
            byte[] buffer = new byte[1024];
            while (!deflater.finished()) {
                int len = deflater.deflate(buffer);
                if (len > 0) bos.write(buffer, 0, len);
            }
            deflater.end();
            return bos.toByteArray();
        }
    }

    /** 解壓縮位元組陣列 */
    public static byte[] decompress(byte[] input) throws IOException {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            Inflater inflater = new Inflater();
            inflater.setInput(input);
            
            byte[] buffer = new byte[1024];
            while (!inflater.finished()) {
                int len = inflater.inflate(buffer);
                if (len <= 0) break; // 防禦性檢查
                bos.write(buffer, 0, len);
            }
            inflater.end();
            return bos.toByteArray();
        }
    }

    /** 壓縮 + Base64 編碼(適合網路傳輸/JSON 嵌入) */
    public static String compressToBase64(byte[] input) throws IOException {
        return Base64.encodeBase64String(compress(input));
    }

    /** Base64 解碼 + 解壓縮 */
    public static byte[] decompressFromBase64(String base64) throws IOException {
        return decompress(Base64.decodeBase64(base64));
    }

    // --- 檔案層級便利方法 ---
    public static void compressFile(File src, File dest) throws IOException {
        try (FileInputStream fis = new FileInputStream(src);
             FileOutputStream fos = new FileOutputStream(dest)) {
            byte[] data = fis.readAllBytes(); // Java 9+
            fos.write(compress(data));
        }
    }

    public static void decompressFile(File src, File dest) throws IOException {
        try (FileInputStream fis = new FileInputStream(src);
             FileOutputStream fos = new FileOutputStream(dest)) {
            byte[] data = fis.readAllBytes();
            fos.write(decompress(data));
        }
    }
}

關鍵細節與避坑指南

1. 必須呼叫 finish()

Deflater 採串流模式,finish() 告知「輸入結束」,才會輸出最後壓縮區塊與校驗碼。漏呼叫會導致輸出不完整、解壓失敗。

2. 迴圈條件用 finished()

deflate() 回傳 0 不代表結束,可能只是緩衝區未滿。必須配合 finished() 判斷。

3. 釋放原生資源

Deflater/Inflater 底層使用 JNI 持有原生記憶體,必須在 finally 區塊呼叫 end(),否則洩漏非堆記憶體。

4. 緩衝區大小調整

1024 位元組為保守值。大檔案建議 8KB~64KB 減少 JNI 呼叫開銷:

byte[] buffer = new byte[32 * 1024]; // 32KB

5. 壓縮等級選擇

Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); // 9: 最高壓縮率,最慢
// Deflater.BEST_SPEED (1), Deflater.DEFAULT_COMPRESSION (-1), Deflater.NO_COMPRESSION (0)

6. Base64 編碼膨脹約 33%

壓縮後再 Base64 編碼體積會增大 1/3,若傳輸協定支援二進位(如 HTTP Body、gRPC),直接傳輸位元組陣列 更高效。

完整測試範例

public class DeflateDemo {
    public static void main(String[] args) throws IOException {
        String original = "Java Deflate 壓縮測試 ".repeat(1000); // ~20KB 文字
        byte[] input = original.getBytes(StandardCharsets.UTF_8);
        
        // 壓縮
        byte[] compressed = DeflateUtils.compress(input);
        System.out.printf("原始: %,d bytes -> 壓縮: %,d bytes (%.1f%%)%n",
            input.length, compressed.length, 100.0 * compressed.length / input.length);
        
        // Base64 編碼模擬網路傳輸
        String b64 = DeflateUtils.compressToBase64(input);
        System.out.println("Base64 長度: " + b64.length());
        
        // 解壓驗證
        byte[] decompressed = DeflateUtils.decompressFromBase64(b64);
        String restored = new String(decompressed, StandardCharsets.UTF_8);
        System.out.println("內容一致: " + original.equals(restored));
    }
}

典型輸出:

原始: 20,000 bytes -> 壓縮: 1,245 bytes (6.2%)
Base64 長度: 1,660
內容一致: true

進階:串流式處理大檔案

避免一次性載入巨大檔案至記憶體,使用 DeflaterOutputStream/InflaterInputStream:

public static void compressStream(InputStream in, OutputStream out) throws IOException {
    try (DeflaterOutputStream dos = new DeflaterOutputStream(out, new Deflater(Deflater.BEST_COMPRESSION))) {
        in.transferTo(dos); // Java 9+
    }
}

public static void decompressStream(InputStream in, OutputStream out) throws IOException {
    try (InflaterInputStream iis = new InflaterInputStream(in)) {
        iis.transferTo(out);
    }
}

總結

  • Deflater/Inflater 是 Java 內建、零依賴的 DEFLATE 實作。
  • 核心流程:setInput → finish → 迴圈 deflate/inflate → end。
  • 務必在 finally 釋放 end(),防止原生記憶體洩漏。
  • 大資料量請使用串流包裝類 DeflaterOutputStream/InflaterInputStream。
  • 網路傳輸需 Base64 時,注意 33% 體積膨脹;優先考慮二進位協定。

掌握此工具類,即可在微服務通訊、日誌壓縮、快取序列化等場景輕鬆套用高效能壓縮。

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