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

Java Base64 編解碼核心原理與手寫實現:RFC 4648 標準、位運算、填充處理

     編輯:Java 程式設計入門

Base64 原理速覽

  • 將 3 位元組 (24 bits) 切為 4 組 6 bits,每組映射到 64 字符表 (`A-Z a-z 0-9 + /`)。
  • 不足 3 位元組時,以 `=` 填充輸出至 4 字符倍數。
  • 標準每 76 字符換行 (MIME),現代常用無換行模式。

編碼表構建

private static final char[] ENCODE_TABLE = new char[64];
private static final byte[] DECODE_TABLE = new byte[256]; // -1 非法

static {
    // 編碼表
    int idx = 0;
    for (char c = 'A'; c <= 'Z'; c++) ENCODE_TABLE[idx++] = c;
    for (char c = 'a'; c <= 'z'; c++) ENCODE_TABLE[idx++] = c;
    for (char c = '0'; c <= '9'; c++) ENCODE_TABLE[idx++] = c;
    ENCODE_TABLE[idx++] = '+'; ENCODE_TABLE[idx++] = '/';

    // 解碼表
    Arrays.fill(DECODE_TABLE, (byte) -1);
    for (int i = 0; i < 64; i++) DECODE_TABLE[ENCODE_TABLE[i]] = (byte) i;
    DECODE_TABLE['='] = -2; // 填充標記
}

編碼實現 (位運算版)

public static String encode(byte[] data) {
    if (data == null) return null;
    int len = data.length;
    if (len == 0) return "";

    int outLen = (len + 2) / 3 * 4; // 含填充
    char[] out = new char[outLen];
    int op = 0, ip = 0;

    while (ip < len) {
        int b0 = data[ip++] & 0xFF;
        int b1 = ip < len ? data[ip++] & 0xFF : 0;
        int b2 = ip < len ? data[ip++] & 0xFF : 0;

        int triple = (b0 << 16) | (b1 << 8) | b2;

        out[op++] = ENCODE_TABLE[(triple >>> 18) & 0x3F];
        out[op++] = ENCODE_TABLE[(triple >>> 12) & 0x3F];
        out[op++] = (ip > len + 1) ? '=' : ENCODE_TABLE[(triple >>> 6) & 0x3F]; // 倒數第二字符
        out[op++] = (ip > len)     ? '=' : ENCODE_TABLE[triple & 0x3F];         // 最後字符
    }
    return new String(out);
}

解碼實現 (嚴格檢查)

public static byte[] decode(String s) throws IllegalArgumentException {
    if (s == null) return null;
    s = s.trim();
    if (s.isEmpty()) return new byte[0];
    if (s.length() % 4 != 0) throw new IllegalArgumentException("長度非 4 倍數");

    // 計算有效字符數 (排除填充)
    int pad = 0;
    if (s.endsWith("==")) pad = 2;
    else if (s.endsWith("=")) pad = 1;

    int dataLen = (s.length() / 4) * 3 - pad;
    byte[] out = new byte[dataLen];
    int op = 0;

    for (int i = 0; i < s.length(); i += 4) {
        int v0 = decodeChar(s.charAt(i));
        int v1 = decodeChar(s.charAt(i+1));
        int v2 = decodeChar(s.charAt(i+2));
        int v3 = decodeChar(s.charAt(i+3));

        int triple = (v0 << 18) | (v1 << 12) | (v2 << 6) | v3;

        out[op++] = (byte) (triple >>> 16);
        if (op < dataLen) out[op++] = (byte) (triple >>> 8);
        if (op < dataLen) out[op++] = (byte) triple;
    }
    return out;
}

private static int decodeChar(char c) {
    if (c >= DECODE_TABLE.length) throw new IllegalArgumentException("非 ASCII 字符: " + c);
    int v = DECODE_TABLE[c];
    if (v < 0) throw new IllegalArgumentException("非法 Base64 字符: " + c);
    return v;
}

URL/檔名安全變體 (RFC 4648 §5)

  • 將 `+` → `-`,`/` → `_`,移除填充 `=`。
  • 適用於 URL 參數、JSON 欄位、檔名,無需額外 URL 編碼。

效能對比 (參考)

實現相對速度備註
手寫位運算 (上述)1.0x基準
Java 8 `Base64.getEncoder()`~1.2x內部使用 `sun.misc.Base64` 或向量化
Apache Commons Codec~0.9x功能豐富但稍慢

生產建議

**直接使用 `java.util.Base64` (Java 8+)**:標準、高效、無依賴、支援 MIME/URL/無填充多種模式。手寫版本僅供教學、面試、極度受限環境 (無 JRE、嵌入式) 參考。

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