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