Java Base64編碼詳解:原理、核心組件及示例代碼

2024-12-16 17:55 更新

Base64 是一種編碼方法,用于將二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成64個(gè)可打印的ASCII字符的序列。這種編碼方式廣泛應(yīng)用于在文本格式中存儲(chǔ)二進(jìn)制數(shù)據(jù),例如在 URL、文件名、或在 XML 和 JSON 文檔中。Java 中的 Base64 編碼和解碼通??梢酝ㄟ^(guò) java.util.Base64 類實(shí)現(xiàn),這個(gè)類在 Java 8 及以后的版本中提供。

以下是V 哥整理的 Java 中 java.util.Base64 類的核心組件,V 哥將重點(diǎn)介紹這些組件的原理和用法:

  1. 編碼器(Encoder)
    • getEncoder():返回一個(gè) Base64.Encoder 實(shí)例,用于將數(shù)據(jù)編碼為 Base64 格式。

  1. 解碼器(Decoder)
    • getDecoder():返回一個(gè) Base64.Decoder 實(shí)例,用于將 Base64 編碼的數(shù)據(jù)解碼回原始格式。

  1. 編碼表(Encoding Table)
    • Base64 編碼器使用一個(gè)靜態(tài)的編碼表來(lái)將字節(jié)映射到 Base64 字符。

  1. 解碼表(Decoding Table)
    • Base64 解碼器使用一個(gè)靜態(tài)的解碼表來(lái)將 Base64 字符映射回字節(jié)。

  1. 編碼模式(Encoding Mode)
    • BASE64:標(biāo)準(zhǔn)的 Base64 編碼模式。
    • URL_SAFE:URL 和文件名安全的 Base64 編碼模式,使用 -_ 代替標(biāo)準(zhǔn)模式中的 +/。

  1. 行長(zhǎng)度和填充
    • Base64 編碼輸出通常每76個(gè)字符會(huì)有一個(gè)換行符,但這可以通過(guò) Encoder 的配置來(lái)改變。

示例代碼:

import java.util.Base64;
import java.nio.charset.StandardCharsets;


public class Base64Example {
    public static void main(String[] args) {
        String original = "Hello, VG!";
        byte[] encoded = Base64.getEncoder().encode(original.getBytes(StandardCharsets.UTF_8));
        System.out.println("Encoded: " + new String(encoded, StandardCharsets.UTF_8));


        byte[] decoded = Base64.getDecoder().decode(encoded);
        System.out.println("Decoded: " + new String(decoded, StandardCharsets.UTF_8));
    }
}

在上述代碼中,我們使用 Base64.getEncoder().encode() 方法將字符串 "Hello, VG!" 編碼為 Base64 格式,然后使用 Base64.getDecoder().decode() 方法將其解碼回原始字符串。

Base64 編碼和解碼的實(shí)現(xiàn)通常依賴于這些核心組件,它們提供了靈活的方式來(lái)處理不同場(chǎng)景下的編碼需求。

小試牛刀后,我們來(lái)一起詳細(xì)看看它們的實(shí)現(xiàn)原理。

1. 編碼器(Encoder)

在 Java 8 引入的 java.util.Base64 包中,Encoder 類是 Base64 類的一個(gè)內(nèi)部類,用于實(shí)現(xiàn) Base64 編碼功能。以下是 Encoder 類實(shí)現(xiàn)的詳細(xì)步驟和原理分析:

1. 初始化編碼器

首先,通過(guò) Base64.getEncoder() 獲取 Encoder 對(duì)象的實(shí)例。這個(gè)實(shí)例包含了編碼過(guò)程中需要的所有配置,例如是否添加填充字符等。

Base64.Encoder encoder = Base64.getEncoder();

2. 準(zhǔn)備編碼數(shù)據(jù)

將需要編碼的數(shù)據(jù)放入字節(jié)數(shù)組中。這些數(shù)據(jù)將作為輸入傳遞給編碼器。

byte[] dataToEncode = "beijing Hot".getBytes(StandardCharsets.UTF_8);

3. 編碼數(shù)據(jù)

使用 Encoder 實(shí)例的 encode 方法對(duì)數(shù)據(jù)進(jìn)行編碼。這個(gè)方法會(huì)返回一個(gè)包含 Base64 編碼結(jié)果的字節(jié)數(shù)組。

byte[] encodedData = encoder.encode(dataToEncode);

4. 處理編碼結(jié)果

編碼后的字節(jié)數(shù)組可以轉(zhuǎn)換為字符串,或者直接寫入到輸出流中。

String encodedString = new String(encodedData, StandardCharsets.UTF_8);

編碼原理

  1. Base64 字符集: Base64 編碼使用一個(gè)包含 64 個(gè)字符的字符集,包括大寫字母 A-Z、a-z、數(shù)字 0-9、加號(hào)(+)和斜杠(/)。

  1. 3 字節(jié)到 4 字符的映射: 每次從輸入數(shù)據(jù)中讀取 3 個(gè)字節(jié)(24 位),然后將這 24 位分割成 4 個(gè) 6 位的組。每個(gè) 6 位組映射到一個(gè) Base64 字符。

  1. 填充: 如果輸入數(shù)據(jù)的字節(jié)數(shù)不是 3 的倍數(shù),在編碼的最后會(huì)添加一個(gè)或兩個(gè) = 字符作為填充。

  1. 換行符: 在編碼過(guò)程中,可以根據(jù)配置在每 76 個(gè)字符后添加換行符,以確保編碼后的文本符合 MIME 的要求。

  1. 無(wú)填充模式: 使用 encoder.withoutPadding() 可以禁用自動(dòng)填充,這樣編碼后的輸出就不會(huì)包含 = 字符。

源碼分析

Base64.Encoder 類中,編碼過(guò)程主要涉及以下幾個(gè)關(guān)鍵部分:

  • 編碼表ENCODE 數(shù)組定義了如何將 6 位二進(jìn)制數(shù)映射到 Base64 字符集。
  • 緩沖區(qū)encoder 內(nèi)部維護(hù)一個(gè)緩沖區(qū),用于存儲(chǔ)待編碼的字節(jié)。
  • 編碼方法encode 方法實(shí)現(xiàn)具體的編碼邏輯,包括從緩沖區(qū)讀取字節(jié)、映射到 Base64 字符、處理剩余字節(jié)和填充。

編碼步驟

  1. 填充緩沖區(qū):將輸入數(shù)據(jù)寫入到 encoder 的內(nèi)部緩沖區(qū)。
  2. 分組:將緩沖區(qū)中的字節(jié)按每 3 個(gè)字節(jié)分為一組。
  3. 映射字符:使用 ENCODE 表將每組的 24 位映射到 4 個(gè) Base64 字符。
  4. 處理剩余:如果最后一組不足 3 個(gè)字節(jié),使用 = 作為填充,并相應(yīng)調(diào)整映射的字符。
  5. 輸出結(jié)果:將映射后的字符輸出或轉(zhuǎn)換為字符串。

來(lái)一個(gè)示例代碼嘗試一下使用

public byte[] encode(byte[] input) {
    // 初始化輸出數(shù)組
    byte[] output = new byte[...];
    int outputPos = 0;


    for (int i = 0; i < input.length; i += 3) {
        // 讀取 3 個(gè)字節(jié)
        int threeBytes = ((input[i] & 0xFF) << 16) |
                         ((i + 1 < input.length) ? (input[i + 1] & 0xFF) << 8 : 0) |
                         ((i + 2 < input.length) ? (input[i + 2] & 0xFF) : 0);


        // 映射到 4 個(gè) Base64 字符
        for (int j = 0; j < 4; j++) {
            int index = (threeBytes & (0xFF << (8 * (3 - j)))) >> (8 * (3 - j));
            output[outputPos++] = ENCODE[index];
        }
    }


    // 處理填充
    if (neededPadding) {
        output[outputPos++] = '=';
        // 可能還需要第二個(gè) '='
    }


    return Arrays.copyOf(output, outputPos);
}

以上代碼演示了 Base64 編碼的基本邏輯,實(shí)際的 Encoder 類實(shí)現(xiàn)可能會(huì)包含更多的細(xì)節(jié),例如處理?yè)Q行符、無(wú)填充模式等。

2. 解碼器(Decoder)

在 Java 8 及以后的版本中,java.util.Base64 包中的 Decoder 類是 Base64 類的一個(gè)內(nèi)部類,用于實(shí)現(xiàn) Base64 解碼功能。以下是 Decoder 類實(shí)現(xiàn)的詳細(xì)步驟和原理分析:

1. 初始化解碼器

首先,通過(guò) Base64.getDecoder() 獲取 Decoder 對(duì)象的實(shí)例。這個(gè)實(shí)例包含了解碼過(guò)程中需要的所有配置。

Base64.Decoder decoder = Base64.getDecoder();

2. 準(zhǔn)備解碼數(shù)據(jù)

將需要解碼的 Base64 字符串轉(zhuǎn)換為字節(jié)數(shù)組。這些數(shù)據(jù)將作為輸入傳遞給解碼器。

String base64String = "SGVsbG8sIFdvcmxkIQ==";
byte[] dataToDecode = base64String.getBytes(StandardCharsets.UTF_8);

3. 解碼數(shù)據(jù)

使用 Decoder 實(shí)例的 decode 方法對(duì) Base64 字符串進(jìn)行解碼。這個(gè)方法會(huì)返回一個(gè)包含原始數(shù)據(jù)的字節(jié)數(shù)組。

byte[] decodedData = decoder.decode(dataToDecode);

4. 處理解碼結(jié)果

解碼后的字節(jié)數(shù)組可以轉(zhuǎn)換為字符串,或者直接用于其他需要原始數(shù)據(jù)的場(chǎng)合。

String decodedString = new String(decodedData, StandardCharsets.UTF_8);

解碼原理

  1. Base64 字符集: Base64 解碼使用與編碼相同的 64 個(gè)字符集,包括大寫字母 A-Z、a-z、數(shù)字 0-9、加號(hào)(+)和斜杠(/)。

  1. 4 字符到 3 字節(jié)的映射: 每次從 Base64 編碼的數(shù)據(jù)中讀取 4 個(gè)字符(24 位),然后將這 24 位分割成 3 個(gè) 8 位的組。每個(gè) 8 位的組映射回原始的字節(jié)。

  1. 處理填充: 如果編碼時(shí)使用了填充字符(=),解碼時(shí)需要識(shí)別并忽略這些字符。

  1. 異常處理: 如果輸入數(shù)據(jù)包含非法字符或格式不正確,解碼過(guò)程將拋出 IllegalArgumentException。

源碼分析

Base64.Decoder 類中,解碼過(guò)程主要涉及以下幾個(gè)關(guān)鍵部分:

  • 解碼表DECODE 數(shù)組定義了 Base64 字符到 6 位二進(jìn)制數(shù)的映射。
  • 緩沖區(qū)decoder 內(nèi)部維護(hù)一個(gè)緩沖區(qū),用于存儲(chǔ)待解碼的 Base64 字符。
  • 解碼方法decode 方法實(shí)現(xiàn)具體的解碼邏輯,包括從輸入讀取字符、映射回字節(jié)、處理填充和非法字符。

解碼步驟

  1. 填充緩沖區(qū):將 Base64 編碼的字符串轉(zhuǎn)換為字節(jié)數(shù)組,并填充到 decoder 的內(nèi)部緩沖區(qū)。
  2. 分組:將緩沖區(qū)中的 Base64 字符按每 4 個(gè)字符分為一組。
  3. 映射字節(jié):使用 DECODE 表將每組的 24 位映射回 3 個(gè)字節(jié)。
  4. 處理填充:如果編碼時(shí)使用了填充,解碼時(shí)識(shí)別 = 字符并相應(yīng)調(diào)整映射的字節(jié)。
  5. 輸出結(jié)果:將映射后的字節(jié)輸出或轉(zhuǎn)換為原始數(shù)據(jù)。

還是上示例看用法

public byte[] decode(byte[] input) {
    // 初始化輸出數(shù)組
    byte[] output = new byte[...];
    int outputPos = 0;


    for (int i = 0; i < input.length; i += 4) {
        // 讀取 4 個(gè) Base64 字符
        int fourChars = (DECODE[input[i] & 0xFF] << 18) |
                        (DECODE[input[i + 1] & 0xFF] << 12) |
                        (DECODE[input[i + 2] & 0xFF] << 6) |
                        (DECODE[input[i + 3] & 0xFF]);


        // 映射回 3 個(gè)字節(jié)
        output[outputPos++] = (fourChars >> 16) & 0xFF;
        if (input[i + 2] != '=') {
            output[outputPos++] = (fourChars >> 8) & 0xFF;
        }
        if (input[i + 3] != '=') {
            output[outputPos++] = fourChars & 0xFF;
        }
    }


    return Arrays.copyOf(output, outputPos);
}

以上的代碼演示了 Base64 解碼的基本邏輯,實(shí)際的 Decoder 類實(shí)現(xiàn)可能會(huì)包含更多的細(xì)節(jié),例如處理非法字符、解碼表的初始化等。

通過(guò)這種方式,Base64.Decoder 提供了一種靈活且高效的方式來(lái)將 Base64 編碼的字符串解碼回原始的字節(jié)數(shù)據(jù),適用于多種不同的解碼需求。

3. 編碼表(Encoding Table)

Base64 編碼表是 Base64 編碼和解碼過(guò)程中的核心組件之一。它是一個(gè)查找表,用于將 6 位二進(jìn)制值映射到相應(yīng)的 Base64 編碼字符。以下是 Base64 編碼表的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:

1. 定義 Base64 字符集

Base64 編碼使用 64 個(gè)可打印的 ASCII 字符來(lái)表示數(shù)據(jù)。這些字符包括大寫字母 A-Z(26 個(gè))、小寫字母 a-z(26 個(gè),但在標(biāo)準(zhǔn) Base64 中通常使用大寫)、數(shù)字 0-9(10 個(gè))、加號(hào) + 和斜杠 /。此外,為了支持 URL 和文件名,還有一個(gè)變種使用 - 代替 +_ 代替 /。

2. 初始化編碼表

在 Java 的 java.util.Base64 類中,編碼表通常是通過(guò)一個(gè)靜態(tài)初始化的數(shù)組來(lái)實(shí)現(xiàn)的。這個(gè)數(shù)組的長(zhǎng)度為 64,正好對(duì)應(yīng)于 Base64 字符集中的字符數(shù)量。

private static final char[] ENCODE = {
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    // ... 省略中間字符
    'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    '+', '/'
};

3. 使用編碼表進(jìn)行編碼

在編碼過(guò)程中,原始數(shù)據(jù)被讀取并轉(zhuǎn)換為字節(jié),然后每三個(gè)字節(jié)(24 位)被轉(zhuǎn)換為四個(gè) 6 位的組。每個(gè) 6 位組的值通過(guò)查找編碼表來(lái)找到對(duì)應(yīng)的 Base64 字符。

4. 處理填充

如果原始數(shù)據(jù)的長(zhǎng)度不是 3 的倍數(shù),最后一組可能只有 1 或 2 個(gè)字節(jié)。在這種情況下,剩余的位使用 = 字符填充。填充字符不通過(guò)編碼表映射,而是直接添加到輸出中。

5. 生成編碼字符串

將映射得到的 Base64 字符連接起來(lái),形成最終的編碼字符串。

原理解釋

  • 6 位映射:由于 Base64 編碼將 3 個(gè)字節(jié)(24 位)轉(zhuǎn)換為 4 個(gè)字符(每個(gè)字符 6 位),所以每個(gè)字符可以表示 6 位二進(jìn)制數(shù)據(jù)。ENCODE 數(shù)組中的每個(gè)索引值對(duì)應(yīng)一個(gè) 6 位的二進(jìn)制數(shù)。
  • 字符選擇:在編碼過(guò)程中,通過(guò)將字節(jié)數(shù)據(jù)的位操作結(jié)果作為索引,從 ENCODE 數(shù)組中選擇相應(yīng)的字符。
  • 性能優(yōu)化:使用查找表可以快速地進(jìn)行字符映射,避免了復(fù)雜的條件判斷或循環(huán),從而提高了編碼的效率。

示例代碼

以下是如何使用編碼表進(jìn)行 Base64 編碼的示例代碼:

public String encode(byte[] data) {
    StringBuilder encoded = new StringBuilder();
    int i = 0;


    while (i < data.length - 2) { // 處理完整組
        int threeBytes = ((data[i] & 0xFF) << 16) |
                         ((data[i + 1] & 0xFF) << 8) |
                         (data[i + 2] & 0xFF);
        // 將 24 位分為 4 個(gè) 6 位組
        for (int j = 0; j < 4; j++) {
            int index = (threeBytes >> (18 - j * 6)) & 0x3F;
            encoded.append(ENCODE[index]);
        }
        i += 3;
    }


    // 處理剩余字節(jié)和填充
    if (i < data.length) {
        int remaining = data.length - i;
        int twoBytes = (data[i] & 0xFF) << (8 * (2 - remaining));
        for (int j = 0; j < remaining; j++) {
            int index = (twoBytes >> (16 - j * 8)) & 0xFF;
            encoded.append(ENCODE[index]);
        }
        // 添加填充字符
        while (encoded.length() % 4 != 0) {
            encoded.append('=');
        }
    }


    return encoded.toString();
}

這個(gè)偽代碼演示了如何使用 Base64 編碼表將字節(jié)數(shù)據(jù)編碼為 Base64 字符串。實(shí)際的 Base64.Encoder 類實(shí)現(xiàn)可能會(huì)包含更多的細(xì)節(jié),例如處理?yè)Q行符等。

4. 解碼表(Decoding Table)

Base64 解碼表是 Base64 編碼和解碼過(guò)程中的另一個(gè)核心組件。它用于將 Base64 編碼的字符映射回相應(yīng)的 6 位二進(jìn)制值。以下是 Base64 解碼表的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:

1. 定義 Base64 字符集

與編碼表一樣,解碼表依賴于 Base64 字符集,包括大寫字母 A-Z、小寫字母 a-z(在標(biāo)準(zhǔn) Base64 中通常不使用)、數(shù)字 0-9、加號(hào) + 和斜杠 /。對(duì)于 URL 安全的 Base64,使用 - 代替 +_ 代替 /。

2. 初始化解碼表

在 Java 的 java.util.Base64 類中,解碼表通常是通過(guò)一個(gè)靜態(tài)初始化的數(shù)組來(lái)實(shí)現(xiàn)的。這個(gè)數(shù)組的長(zhǎng)度為 128,覆蓋了所有可能的 ASCII 字符,因?yàn)闃?biāo)準(zhǔn) ASCII 字符集大小為 128 個(gè)字符。

private static final int[] DECODE = new int[128];

在靜態(tài)初始化塊中,解碼表被填充。每個(gè) Base64 字符都被賦予一個(gè)值,從 0 到 63,而非法字符則通常被賦予 -1 或其他表示無(wú)效的值。

static {
    for (int i = 0; i < DECODE.length; i++) {
        DECODE[i] = -1; // 初始值設(shè)為無(wú)效
    }
    // 為 Base64 字符賦值
    for (int i = 'A'; i <= 'Z'; i++) {
        DECODE[i] = i - 'A';
    }
    for (int i = 'a'; i <= 'z'; i++) {
        DECODE[i] = 26 + i - 'a';
    }
    for (int i = '0'; i <= '9'; i++) {
        DECODE[i] = 52 + i - '0';
    }
    DECODE['+'] = 62;
    DECODE['/'] = 63;
    // 對(duì)于 URL 安全的 Base64,可以添加以下賦值
    DECODE['-'] = 62;
    DECODE['_'] = 63;
}

3. 使用解碼表進(jìn)行解碼

在解碼過(guò)程中,Base64 編碼的字符串被逐個(gè)字符讀取,每個(gè)字符通過(guò)解碼表轉(zhuǎn)換為其對(duì)應(yīng)的 6 位二進(jìn)制值。

4. 處理填充

Base64 編碼可能以 = 字符結(jié)尾,表示原始數(shù)據(jù)在編碼時(shí)不足 3 個(gè)字節(jié)。在解碼時(shí),這些填充字符被忽略,不參與解碼過(guò)程。

5. 生成原始數(shù)據(jù)

將解碼得到的 6 位二進(jìn)制值重新組合,轉(zhuǎn)換回原始的字節(jié)序列。

原理解釋

  • 字符到值的映射:解碼表提供了從 Base64 字符到其對(duì)應(yīng)的 6 位二進(jìn)制值的快速映射。這種映射是通過(guò)查找表實(shí)現(xiàn)的,其中每個(gè)可能的字符(128 個(gè) ASCII 字符)都有一個(gè)與之對(duì)應(yīng)的整數(shù)值。
  • 忽略非法字符:解碼表中的非法字符被賦予一個(gè)特殊值(如 -1),在解碼過(guò)程中,這些值被忽略或?qū)е陆獯a失敗。
  • 性能優(yōu)化:使用查找表可以快速地進(jìn)行字符到值的轉(zhuǎn)換,避免了復(fù)雜的條件判斷或循環(huán),從而提高了解碼的效率。

上示例代碼

以下是如何使用解碼表進(jìn)行 Base64 解碼的示例代碼:

public byte[] decode(String encoded) {
    char[] chars = encoded.toCharArray();
    int[] decodeTable = getDecodeTable(); // 獲取初始化的解碼表
    ByteArrayOutputStream output = new ByteArrayOutputStream();

    
    for (int i = 0; i < chars.length;) {
        if (chars[i] == '=') { // 處理填充
            break;
        }
        int value = decodeTable[chars[i] & 0xFF];
        if (value == -1) { // 非法字符
            throw new IllegalArgumentException("Illegal character encountered");
        }
        // 將 4 個(gè) Base64 字符轉(zhuǎn)換為 3 個(gè)字節(jié)
        int threeBytes = (value << 18) |
                         (decodeTable[chars[++i] & 0xFF] << 12) |
                         (decodeTable[chars[++i] & 0xFF] << 6) |
                         decodeTable[chars[++i] & 0xFF];
        output.write((threeBytes >> 16) & 0xFF);
        if (chars[++i] != '=') {
            output.write((threeBytes >> 8) & 0xFF);
        }
        if (chars[++i] != '=') {
            output.write(threeBytes & 0xFF);
        }
        i++; // 跳過(guò)最后一個(gè)字符,如果它是填充字符
    }

    
    return output.toByteArray();
}

以上代碼演示如何使用 Base64 解碼表將 Base64 編碼的字符串解碼為原始字節(jié)數(shù)組。實(shí)際的 Base64.Decoder 類實(shí)現(xiàn)可能會(huì)包含更多的細(xì)節(jié),例如處理不同編碼模式等。

5. 編碼模式(Encoding Mode)

在 Java 的 java.util.Base64 包中,編碼模式(Encoding Mode)決定了 Base64 編碼的行為,包括字符集的使用和是否添加換行符。以下是對(duì)編碼模式的源碼實(shí)現(xiàn)過(guò)程步驟和原理的詳細(xì)分析:

1. 定義編碼模式

Java 的 Base64 類提供了兩種編碼模式:

  • BASE64:標(biāo)準(zhǔn)的 Base64 編碼模式,使用 A-Z、a-z、0-9+/ 字符,并且可以在每 76 個(gè)字符后添加換行符。
  • URL_SAFE:URL 安全的 Base64 編碼模式,使用 A-Z、a-z、0-9-_ 字符,適用于 URL 和文件名,也不添加換行符。

2. 初始化編碼器

編碼器可以通過(guò) Base64.getEncoder() 獲取,并根據(jù)需要選擇編碼模式。例如,使用 URL 安全模式可以通過(guò) encoder = Base64.getUrlEncoder() 實(shí)現(xiàn)。

3. 配置編碼器

編碼器可以進(jìn)一步配置以滿足特定的編碼需求,例如禁用換行符或填充字符。這些配置可以通過(guò)編碼器的方法鏈調(diào)用來(lái)完成。

Base64.Encoder encoder = Base64.getEncoder();
encoder = encoder.withoutPadding(); // 禁用填充

4. 編碼數(shù)據(jù)

使用配置好的編碼器對(duì)數(shù)據(jù)進(jìn)行編碼。編碼過(guò)程會(huì)根據(jù)編碼模式使用不同的字符集,并根據(jù)配置決定是否添加換行符。

byte[] encodedData = encoder.encode(originalData);

5. 輸出編碼結(jié)果

編碼后的數(shù)據(jù)可以作為字節(jié)數(shù)組或轉(zhuǎn)換為字符串進(jìn)行輸出。

String encodedString = new String(encodedData, StandardCharsets.UTF_8);

原理解釋

  • 字符集選擇:不同的編碼模式使用不同的字符集。標(biāo)準(zhǔn)模式使用 +/,而 URL 安全模式使用 -_ 代替,以避免在 URL 中引起歧義。
  • 換行符處理:在標(biāo)準(zhǔn) Base64 編碼中,為了提高可讀性,每 76 個(gè)字符后可以添加一個(gè)換行符。在 URL 安全模式或當(dāng)禁用換行符時(shí),不添加換行符。
  • 填充處理:當(dāng)輸入數(shù)據(jù)不是 3 個(gè)字節(jié)的倍數(shù)時(shí),Base64 編碼會(huì)在結(jié)果的末尾添加一個(gè)或兩個(gè) = 字符作為填充。通過(guò)配置編碼器,可以禁用這種自動(dòng)填充。

上示例代碼

以下是使用不同編碼模式進(jìn)行 Base64 編碼的示例:

import java.util.Base64;


public class Base64EncodingExample {
    public static void main(String[] args) {
        byte[] data = "Some data to encode".getBytes(StandardCharsets.UTF_8);


        // 使用標(biāo)準(zhǔn) Base64 編碼模式
        Base64.Encoder standardEncoder = Base64.getEncoder();
        String standardEncoded = new String(standardEncoder.encode(data));


        // 使用 URL 安全的 Base64 編碼模式
        Base64.Encoder urlSafeEncoder = Base64.getUrlEncoder().withoutPadding();
        String urlSafeEncoded = new String(urlSafeEncoder.encode(data));


        System.out.println("Standard Encoded: " + standardEncoded);
        System.out.println("URL Safe Encoded: " + urlSafeEncoded);
    }
}

在這個(gè)示例中,我們使用標(biāo)準(zhǔn) Base64 編碼模式和 URL 安全 Base64 編碼模式對(duì)相同的數(shù)據(jù)進(jìn)行編碼,并輸出編碼結(jié)果。

注意事項(xiàng)

  • 編碼模式的選擇應(yīng)根據(jù)數(shù)據(jù)的使用場(chǎng)景來(lái)決定。例如,當(dāng)數(shù)據(jù)將被用于 URL 傳輸時(shí),應(yīng)使用 URL 安全模式。
  • 配置編碼器時(shí),應(yīng)考慮到接收端的解碼能力,確保編碼和解碼使用相同的模式和配置。
  • 禁用填充可能會(huì)影響某些協(xié)議或應(yīng)用程序的兼容性,因?yàn)樗鼈兛赡芷谕?Base64 編碼的數(shù)據(jù)以 = 字符結(jié)束。

通過(guò)這種方式,Base64 類的編碼模式提供了靈活性,以適應(yīng)不同的編碼需求和使用場(chǎng)景。

6. 行長(zhǎng)度和填充

在 Java 的 java.util.Base64 包中,行長(zhǎng)度(line length)和填充(padding)是 Base64 編碼過(guò)程中的兩個(gè)可選配置,它們影響編碼輸出的格式。以下是行長(zhǎng)度和填充的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:

1. 定義行長(zhǎng)度和填充的默認(rèn)行為

在 Base64 編碼中,可以設(shè)置每行的字符數(shù)(行長(zhǎng)度),以及是否在編碼數(shù)據(jù)的末尾添加填充字符 =。

  • 行長(zhǎng)度:默認(rèn)情況下,每行包含 76 個(gè)字符,這是為了確保編碼后的文本符合 MIME 的要求。
  • 填充:如果編碼的數(shù)據(jù)不是 3 個(gè)字節(jié)的倍數(shù),編碼后的輸出會(huì)在末尾添加一個(gè)或兩個(gè) = 字符作為填充。

2. 配置編碼器

編碼器可以通過(guò)調(diào)用 Base64.getEncoder() 獲取,并使用 withoutPadding() 方法來(lái)配置不使用填充。

Base64.Encoder encoder = Base64.getEncoder().withoutPadding();

3. 實(shí)現(xiàn)自定義行分隔

雖然 Java 的 Base64.Encoder 沒(méi)有直接提供設(shè)置行長(zhǎng)度的方法,但你可以通過(guò)自定義編碼邏輯來(lái)實(shí)現(xiàn)。例如,你可以在編碼后的結(jié)果上手動(dòng)插入換行符。

4. 編碼數(shù)據(jù)

使用配置好的編碼器對(duì)數(shù)據(jù)進(jìn)行編碼。編碼過(guò)程會(huì)根據(jù)是否配置了無(wú)填充來(lái)決定是否在輸出末尾添加 = 字符。

byte[] encodedData = encoder.encode(originalData);

5. 手動(dòng)處理行分隔

如果你需要自定義行長(zhǎng)度,可以在編碼后的結(jié)果上手動(dòng)添加換行符。這可以通過(guò)遍歷編碼后的字節(jié)數(shù)組并每隔一定數(shù)量的字符插入一個(gè)換行符來(lái)實(shí)現(xiàn)。

原理解釋

  • 行長(zhǎng)度:設(shè)置行長(zhǎng)度的目的是在編碼后的文本中添加可讀性,使其更適合在文本環(huán)境中展示和編輯。每 76 個(gè) Base64 字符后添加一個(gè)換行符是 Base64 編碼的常見(jiàn)約定。
  • 填充:Base64 編碼要求每三個(gè)字節(jié)的原始數(shù)據(jù)轉(zhuǎn)換為四個(gè) Base64 字符。如果原始數(shù)據(jù)的字節(jié)數(shù)不是 3 的倍數(shù),編碼器會(huì)在結(jié)果末尾添加一個(gè)或兩個(gè) = 字符來(lái)填充。這表明編碼的數(shù)據(jù)不是原始數(shù)據(jù)的完整表示。
  • 自定義行分隔:在某些情況下,你可能需要不同于默認(rèn)行長(zhǎng)度的編碼格式。通過(guò)在編碼后的字符串中手動(dòng)插入換行符,可以實(shí)現(xiàn)自定義行分隔。

示例代碼

以下是如何使用 Base64.Encoder 進(jìn)行編碼,并手動(dòng)添加自定義行分隔的示例:

import java.util.Base64;
import java.io.ByteArrayOutputStream;


public class Base64CustomLineLength {
    public static void main(String[] args) {
        String original = "Some data to encode";
        byte[] data = original.getBytes(StandardCharsets.UTF_8);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Base64.Encoder encoder = Base64.getEncoder().withoutPadding();


        try {
            encoder.encode(data, baos);
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }


        String encoded = baos.toString();
        // 手動(dòng)添加自定義行分隔,例如每 50 個(gè)字符
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < encoded.length(); i += 50) {
            sb.append(encoded, i, Math.min(i + 50, encoded.length()));
            if (i + 50 < encoded.length()) {
                sb.append("\n"); // 添加換行符
            }
        }
        encoded = sb.toString();


        System.out.println("Custom line length encoded: " + encoded);
    }
}

在這個(gè)示例中,我們使用 Base64.Encoder 對(duì)數(shù)據(jù)進(jìn)行編碼,并在編碼后的結(jié)果上手動(dòng)添加了每 50 個(gè)字符的換行符,實(shí)現(xiàn)了自定義行長(zhǎng)度的效果。

注意事項(xiàng)

  • 自定義行分隔可能會(huì)影響編碼數(shù)據(jù)的解碼,確保解碼時(shí)也考慮到了行分隔的處理。
  • 禁用填充可能會(huì)影響某些協(xié)議或應(yīng)用程序的兼容性,因?yàn)樗鼈兛赡芷谕?Base64 編碼的數(shù)據(jù)以 = 字符結(jié)束。
  • 在手動(dòng)添加行分隔時(shí),確保換行符的使用符合目標(biāo)格式的要求。

最后

以上就是 Base64的核心類庫(kù)的全部介紹,了解 Base64的用法和原理,向高手靠近一點(diǎn)點(diǎn)。關(guān)注威哥愛(ài)編程。

Java Base64編碼詳解:原理、核心組件及示例代碼Java Base64編碼詳解:原理、核心組件及示例代碼

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)