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)介紹這些組件的原理和用法:
getEncoder()
:返回一個(gè) Base64.Encoder
實(shí)例,用于將數(shù)據(jù)編碼為 Base64 格式。getDecoder()
:返回一個(gè) Base64.Decoder
實(shí)例,用于將 Base64 編碼的數(shù)據(jù)解碼回原始格式。BASE64
:標(biāo)準(zhǔn)的 Base64 編碼模式。URL_SAFE
:URL 和文件名安全的 Base64 編碼模式,使用 -
和 _
代替標(biāo)準(zhǔn)模式中的 +
和 /
。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)原理。
在 Java 8 引入的 java.util.Base64
包中,Encoder
類是 Base64
類的一個(gè)內(nèi)部類,用于實(shí)現(xiàn) Base64 編碼功能。以下是 Encoder
類實(shí)現(xiàn)的詳細(xì)步驟和原理分析:
首先,通過(guò) Base64.getEncoder()
獲取 Encoder
對(duì)象的實(shí)例。這個(gè)實(shí)例包含了編碼過(guò)程中需要的所有配置,例如是否添加填充字符等。
Base64.Encoder encoder = Base64.getEncoder();
將需要編碼的數(shù)據(jù)放入字節(jié)數(shù)組中。這些數(shù)據(jù)將作為輸入傳遞給編碼器。
byte[] dataToEncode = "beijing Hot".getBytes(StandardCharsets.UTF_8);
使用 Encoder
實(shí)例的 encode
方法對(duì)數(shù)據(jù)進(jìn)行編碼。這個(gè)方法會(huì)返回一個(gè)包含 Base64 編碼結(jié)果的字節(jié)數(shù)組。
byte[] encodedData = encoder.encode(dataToEncode);
編碼后的字節(jié)數(shù)組可以轉(zhuǎn)換為字符串,或者直接寫入到輸出流中。
String encodedString = new String(encodedData, StandardCharsets.UTF_8);
=
字符作為填充。encoder.withoutPadding()
可以禁用自動(dòng)填充,這樣編碼后的輸出就不會(huì)包含 =
字符。
在 Base64.Encoder
類中,編碼過(guò)程主要涉及以下幾個(gè)關(guān)鍵部分:
ENCODE
數(shù)組定義了如何將 6 位二進(jìn)制數(shù)映射到 Base64 字符集。encoder
內(nèi)部維護(hù)一個(gè)緩沖區(qū),用于存儲(chǔ)待編碼的字節(jié)。encode
方法實(shí)現(xiàn)具體的編碼邏輯,包括從緩沖區(qū)讀取字節(jié)、映射到 Base64 字符、處理剩余字節(jié)和填充。encoder
的內(nèi)部緩沖區(qū)。ENCODE
表將每組的 24 位映射到 4 個(gè) Base64 字符。=
作為填充,并相應(yīng)調(diào)整映射的字符。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ú)填充模式等。
在 Java 8 及以后的版本中,java.util.Base64
包中的 Decoder
類是 Base64
類的一個(gè)內(nèi)部類,用于實(shí)現(xiàn) Base64 解碼功能。以下是 Decoder
類實(shí)現(xiàn)的詳細(xì)步驟和原理分析:
首先,通過(guò) Base64.getDecoder()
獲取 Decoder
對(duì)象的實(shí)例。這個(gè)實(shí)例包含了解碼過(guò)程中需要的所有配置。
Base64.Decoder decoder = Base64.getDecoder();
將需要解碼的 Base64 字符串轉(zhuǎn)換為字節(jié)數(shù)組。這些數(shù)據(jù)將作為輸入傳遞給解碼器。
String base64String = "SGVsbG8sIFdvcmxkIQ==";
byte[] dataToDecode = base64String.getBytes(StandardCharsets.UTF_8);
使用 Decoder
實(shí)例的 decode
方法對(duì) Base64 字符串進(jìn)行解碼。這個(gè)方法會(huì)返回一個(gè)包含原始數(shù)據(jù)的字節(jié)數(shù)組。
byte[] decodedData = decoder.decode(dataToDecode);
解碼后的字節(jié)數(shù)組可以轉(zhuǎn)換為字符串,或者直接用于其他需要原始數(shù)據(jù)的場(chǎng)合。
String decodedString = new String(decodedData, StandardCharsets.UTF_8);
=
),解碼時(shí)需要識(shí)別并忽略這些字符。IllegalArgumentException
。
在 Base64.Decoder
類中,解碼過(guò)程主要涉及以下幾個(gè)關(guān)鍵部分:
DECODE
數(shù)組定義了 Base64 字符到 6 位二進(jìn)制數(shù)的映射。decoder
內(nèi)部維護(hù)一個(gè)緩沖區(qū),用于存儲(chǔ)待解碼的 Base64 字符。decode
方法實(shí)現(xiàn)具體的解碼邏輯,包括從輸入讀取字符、映射回字節(jié)、處理填充和非法字符。decoder
的內(nèi)部緩沖區(qū)。DECODE
表將每組的 24 位映射回 3 個(gè)字節(jié)。=
字符并相應(yīng)調(diào)整映射的字節(jié)。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ù),適用于多種不同的解碼需求。
Base64 編碼表是 Base64 編碼和解碼過(guò)程中的核心組件之一。它是一個(gè)查找表,用于將 6 位二進(jìn)制值映射到相應(yīng)的 Base64 編碼字符。以下是 Base64 編碼表的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:
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è)變種使用 -
代替 +
和 _
代替 /
。
在 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',
'+', '/'
};
在編碼過(guò)程中,原始數(shù)據(jù)被讀取并轉(zhuǎn)換為字節(jié),然后每三個(gè)字節(jié)(24 位)被轉(zhuǎn)換為四個(gè) 6 位的組。每個(gè) 6 位組的值通過(guò)查找編碼表來(lái)找到對(duì)應(yīng)的 Base64 字符。
如果原始數(shù)據(jù)的長(zhǎng)度不是 3 的倍數(shù),最后一組可能只有 1 或 2 個(gè)字節(jié)。在這種情況下,剩余的位使用 =
字符填充。填充字符不通過(guò)編碼表映射,而是直接添加到輸出中。
將映射得到的 Base64 字符連接起來(lái),形成最終的編碼字符串。
ENCODE
數(shù)組中的每個(gè)索引值對(duì)應(yīng)一個(gè) 6 位的二進(jìn)制數(shù)。ENCODE
數(shù)組中選擇相應(yīng)的字符。以下是如何使用編碼表進(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行符等。
Base64 解碼表是 Base64 編碼和解碼過(guò)程中的另一個(gè)核心組件。它用于將 Base64 編碼的字符映射回相應(yīng)的 6 位二進(jìn)制值。以下是 Base64 解碼表的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:
與編碼表一樣,解碼表依賴于 Base64 字符集,包括大寫字母 A-Z
、小寫字母 a-z
(在標(biāo)準(zhǔn) Base64 中通常不使用)、數(shù)字 0-9
、加號(hào) +
和斜杠 /
。對(duì)于 URL 安全的 Base64,使用 -
代替 +
和 _
代替 /
。
在 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;
}
在解碼過(guò)程中,Base64 編碼的字符串被逐個(gè)字符讀取,每個(gè)字符通過(guò)解碼表轉(zhuǎn)換為其對(duì)應(yīng)的 6 位二進(jìn)制值。
Base64 編碼可能以 =
字符結(jié)尾,表示原始數(shù)據(jù)在編碼時(shí)不足 3 個(gè)字節(jié)。在解碼時(shí),這些填充字符被忽略,不參與解碼過(guò)程。
將解碼得到的 6 位二進(jìn)制值重新組合,轉(zhuǎn)換回原始的字節(jié)序列。
以下是如何使用解碼表進(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é),例如處理不同編碼模式等。
在 Java 的 java.util.Base64
包中,編碼模式(Encoding Mode)決定了 Base64 編碼的行為,包括字符集的使用和是否添加換行符。以下是對(duì)編碼模式的源碼實(shí)現(xiàn)過(guò)程步驟和原理的詳細(xì)分析:
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 和文件名,也不添加換行符。
編碼器可以通過(guò) Base64.getEncoder()
獲取,并根據(jù)需要選擇編碼模式。例如,使用 URL 安全模式可以通過(guò) encoder = Base64.getUrlEncoder()
實(shí)現(xiàn)。
編碼器可以進(jìn)一步配置以滿足特定的編碼需求,例如禁用換行符或填充字符。這些配置可以通過(guò)編碼器的方法鏈調(diào)用來(lái)完成。
Base64.Encoder encoder = Base64.getEncoder();
encoder = encoder.withoutPadding(); // 禁用填充
使用配置好的編碼器對(duì)數(shù)據(jù)進(jìn)行編碼。編碼過(guò)程會(huì)根據(jù)編碼模式使用不同的字符集,并根據(jù)配置決定是否添加換行符。
byte[] encodedData = encoder.encode(originalData);
編碼后的數(shù)據(jù)可以作為字節(jié)數(shù)組或轉(zhuǎn)換為字符串進(jìn)行輸出。
String encodedString = new String(encodedData, StandardCharsets.UTF_8);
+
和 /
,而 URL 安全模式使用 -
和 _
代替,以避免在 URL 中引起歧義。=
字符作為填充。通過(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é)果。
=
字符結(jié)束。
通過(guò)這種方式,Base64
類的編碼模式提供了靈活性,以適應(yīng)不同的編碼需求和使用場(chǎng)景。
在 Java 的 java.util.Base64
包中,行長(zhǎng)度(line length)和填充(padding)是 Base64 編碼過(guò)程中的兩個(gè)可選配置,它們影響編碼輸出的格式。以下是行長(zhǎng)度和填充的源碼實(shí)現(xiàn)過(guò)程步驟和原理分析:
在 Base64 編碼中,可以設(shè)置每行的字符數(shù)(行長(zhǎng)度),以及是否在編碼數(shù)據(jù)的末尾添加填充字符 =
。
=
字符作為填充。
編碼器可以通過(guò)調(diào)用 Base64.getEncoder()
獲取,并使用 withoutPadding()
方法來(lái)配置不使用填充。
Base64.Encoder encoder = Base64.getEncoder().withoutPadding();
雖然 Java 的 Base64.Encoder
沒(méi)有直接提供設(shè)置行長(zhǎng)度的方法,但你可以通過(guò)自定義編碼邏輯來(lái)實(shí)現(xiàn)。例如,你可以在編碼后的結(jié)果上手動(dòng)插入換行符。
使用配置好的編碼器對(duì)數(shù)據(jù)進(jìn)行編碼。編碼過(guò)程會(huì)根據(jù)是否配置了無(wú)填充來(lái)決定是否在輸出末尾添加 =
字符。
byte[] encodedData = encoder.encode(originalData);
如果你需要自定義行長(zhǎng)度,可以在編碼后的結(jié)果上手動(dòng)添加換行符。這可以通過(guò)遍歷編碼后的字節(jié)數(shù)組并每隔一定數(shù)量的字符插入一個(gè)換行符來(lái)實(shí)現(xiàn)。
=
字符來(lái)填充。這表明編碼的數(shù)據(jù)不是原始數(shù)據(jù)的完整表示。
以下是如何使用 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)度的效果。
=
字符結(jié)束。以上就是 Base64的核心類庫(kù)的全部介紹,了解 Base64的用法和原理,向高手靠近一點(diǎn)點(diǎn)。關(guān)注威哥愛(ài)編程。
Java Base64編碼詳解:原理、核心組件及示例代碼Java Base64編碼詳解:原理、核心組件及示例代碼
更多建議: