轉自:https://juejin.im/post/5c99b2976fb9a070e76376cc
Java 8會因為將lambdas,流,新的日期/時間模型和Nashorn JavaScript引擎引入Java而被記住。有些人還會記得Java 8,因為它引入了各種小但有用的功能,例如Base64 API。什么是Base64以及如何使用此API?這篇文章回答了這些問題。
什么是Base64?
在RFC 1421中首次描述了Base64(但沒有命名):Internet電子郵件的隱私增強:第一部分:消息加密和認證過程。后來,它在RFC 2045中正式呈現為Base64 :多用途Internet郵件擴展(MIME)第一部分:Internet消息體的格式,隨后在RFC 4648:Base16,Base32和Base64數據編碼中重新訪問。
Base64用於防止數據在傳輸過程中通過信息系統(例如電子郵件)進行修改,這些信息系統可能不是8-bit clean(它們可能是8位值)。例如,您將圖像附加到電子郵件消息,並希望圖像到達另一端而不會出現亂碼。您的電子郵件軟件對圖像進行Base64編碼並將等效文本插入到郵件中,如下圖所示:
Content-Disposition: inline;
filename=IMG_0006.JPG
Content-Transfer-Encoding: base64
/9j/4R/+RXhpZgAATU0AKgAAAAgACgEPAAIAAAAGAAAAhgEQAAIAAAAKAAAAjAESAAMAAAABAAYA
AAEaAAUAAAABAAAAlgEbAAUAAAABAAAAngEoAAMAAAABAAIAAAExAAIAAAAHAAAApgEyAAIAAAAU
AAAArgITAAMAAAABAAEAAIdpAAQAAAABAAAAwgAABCRBcHBsZQBpUGhvbmUgNnMAAAAASAAAAAEA
...
NOMbnDUk2bGh26x2yiJcsoBIrvtPe3muBbTRGMdeufmH+Nct4chUXpwSPk/qK9GtJRMWWVFbZ0JH
I4rf2dkZSbOjt7hhEzwcujA4I7Gust75pYVwAPpXn+kzNLOVYD7xFegWEKPkHsM/pU1F0NKbNS32
o24sSCOlaaFYLUhjky4x9PSsKL5bJsdWkAz3xirH2dZLy1DM2C44zx1FZqL2PTXY/9k=
插圖顯示此編碼圖像以/
開頭和結尾=
。在...
表明未展示的文字。請注意,此示例或任何其他示例的整個編碼比原始二進制數據大大約33%。
收件人的電子郵件軟件將對編碼的文本圖像進行Base64解碼,以恢復原始二進制圖像。對於此示例,圖像將與消息的其余部分一起顯示。
Base64編碼和解碼
Base64依賴於簡單的編碼和解碼算法。它們使用65個字符的US-ASCII子集,其中前64個字符中的每一個都映射到等效的6位二進制序列。這是字母表:
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
第65個字符(=
)用於將Base64編碼的文本填充到整數大小,如下所述。
編碼算法接收8位字節的輸入流。假定該流首先以最高有效位排序:第一位是第一個字節中的高位,第八位是該字節中的低位,依此類推。
從左到右,這些字節被組織成24位組。每組被視為四個連接的6位組。每個6位組索引為64個可打印字符的數組; 輸出結果字符。
當在編碼數據的末尾有少於24位可用時,添加零位(在右側)以形成整數個6位組。然后,可以輸出一個或兩個=
填充字符。有兩種情況需要考慮:
- 一個剩余字節:將四個零位附加到該字節以形成兩個6位組。每個組索引數組並輸出結果字符。在這兩個字符之后,輸出兩個
=
填充字符。 - 剩下的兩個字節:兩個零位附加到第二個字節,形成三個6位組。每個組索引數組並輸出結果字符。在這三個字符之后,輸出一個
=
填充字符。
讓我們考慮三個例子來了解編碼算法的工作原理。首先,假設我們希望編碼@!*
:
Source ASCII bit sequences with prepended 0 bits to form 8-bit bytes:
@ ! *
01000000 00100001 00101010
Dividing this 24-bit group into four 6-bit groups yields the following:
010000 | 000010 | 000100 | 101010
These bit patterns equate to the following indexes:
16 2 4 42
Indexing into the Base64 alphabet shown earlier yields the following encoding:
QCEq
我們將繼續將輸入序列縮短為@!
:
Source ASCII bit sequences with prepended 0 bits to form 8-bit bytes:
@ !
01000000 00100001
Two zero bits are appended to make three 6-bit groups:
010000 | 000010 | 000100
These bit patterns equate to the following indexes:
16 2 4
Indexing into the Base64 alphabet shown earlier yields the following encoding:
QCE
An = pad character is output, yielding the following final encoding:
QCE=
最后一個示例將輸入序列縮短為@
:
Source ASCII bit sequence with prepended 0 bits to form 8-bit byte:
@
01000000
Four zero bits are appended to make two 6-bit groups:
010000 | 000000
These bit patterns equate to the following indexes:
16 0
Indexing into the Base64 alphabet shown earlier yields the following encoding:
QA
Two = pad characters are output, yielding the following final encoding:
QA==
解碼算法是編碼算法的逆。但是,檢測到不在Base64字母表中的字符或填充字符數不正確時,可以自由采取適當的措施。
Base64變種
已經設計了幾種Base64變體。一些變體要求編碼的輸出流被分成多行固定長度,每行不超過一定的長度限制,並且(最后一行除外)通過行分隔符與下一行分開(回車\r
后跟一行換行\n
)。我描述了Java 8的Base64 API支持的三種變體。查看Wikipedia的Base64條目以獲取完整的變體列表。
Basic
RFC 4648描述了一種稱為
的Base64變體。此變體使用RFC 4648和RFC 2045的表1中所示的Base64字母表(並在本文前面所示)進行編碼和解碼。編碼器將編碼的輸出流視為一行; 沒有輸出行分隔符。解碼器拒絕包含Base64字母表之外的字符的編碼。請注意,可以覆蓋這些和其他規定。
MIME
RFC 2045描述了一種稱為
的Base64變體。此變體使用RFC 2045的表1中提供的Base64字母表進行編碼和解碼。編碼的輸出流被組織成不超過76個字符的行; 每行(最后一行除外)通過行分隔符與下一行分隔。解碼期間將忽略Base64字母表中未找到的所有行分隔符或其他字符。
URL and Filename Safe
RFC 4648描述了一種稱為
的Base64變體。此變體使用RFC 4648的表2中提供的Base64字母表進行編碼和解碼。字母表與前面顯示的字母相同,只是-
替換+
和_
替換/
。不輸出行分隔符。解碼器拒絕包含Base64字母表之外的字符的編碼。
Base64編碼在冗長的二進制數據和HTTP GET請求的上下文中很有用。我們的想法是對這些數據進行編碼,然后將其附加到HTTP GET URL。如果使用Basic或MIME變體,則編碼數據中的任何+
或/
字符必須被URL編碼為十六進制序列(+
變為%2B
和/
變為%2F
)。生成的URL字符串會稍長一些。通過更換+
同-
和/
同_
,URL和文件名安全消除了對URL編碼器/解碼器(和它們的編碼值的長度影響)的需要。此外,當編碼數據用於文件名時,此變體很有用,因為Unix和Windows文件名不能包含/
。
使用Java的Base64 API
Java 8引入一個Base64 API,包括java.util.Base64
類及其嵌套static
類Encoder
和Decoder
。Base64
有幾種獲取編碼器和解碼器的static
方法:
Base64.Encoder getEncoder()
:返回Basic變體的編碼器。Base64.Decoder getDecoder()
:返回Basic變體的解碼器。Base64.Encoder getMimeEncoder()
:返回MIME變體的編碼器。Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator)
:返回具有給定lineLength
的已修改MIME變體的編碼器(向下舍入到最接近的4的倍數 - 輸出在lineLength
<= 0 時不分成行)和lineSeparator
。當lineSeparator
包含RFC 2045的表1中列出的任何Base64字母字符時,它會拋出java.lang.IllegalArgumentException
。getMimeEncoder()
方法返回的RFC 2045編碼器是相當嚴格的。例如,該編碼器創建具有76個字符的固定行長度(最后一行除外)的編碼文本。如果您希望編碼器支持RFC 1421,它指定固定行長度為64個字符,則需要使用getMimeEncoder(int lineLength, byte[] lineSeparator)
。Base64.Decoder getMimeDecoder()
:返回MIME變體的解碼器。Base64.Encoder getUrlEncoder()
:返回URL和Filename Safe變體的編碼器。Base64.Decoder getUrlDecoder()
:返回URL和Filename Safe變體的解碼器。
Base64.Encoder
提出了幾種用於編碼字節序列的線程安全實例方法 將空引用傳遞給以下方法之一會導致java.lang.NullPointerException
:
byte[] encode(byte[] src)
:將src
所有字節編碼到新分配的字節數組中,然后返回結果。int encode(byte[] src, byte[] dst)
:編碼src
所有字節到dst
(開始於偏移0)。如果dst
不足以保存編碼,則拋出IllegalArgumentException
。否則,返回寫入dst
的字節數。ByteBuffer encode(ByteBuffer buffer)
:將buffer
所有剩余字節編碼到新分配的java.nio.ByteBuffer
對象中。返回后,buffer
的position將更新到它的limit; 它的limit不會改變。返回的輸出緩沖區的position將為零,其limit將是結果編碼字節的數量。String encodeToString(byte[] src)
:將src
所有字節編碼為一個字符串,並返回該字符串。調用此方法等同於執行new String(encode(src), StandardCharsets.ISO_8859_1)
。Base64.Encoder withoutPadding()
:返回與此編碼器等效編碼的編碼器,但不在編碼字節數據的末尾添加任何填充字符。OutputStream wrap(OutputStream os)
:包裝輸出流以編碼字節數據。建議在使用后立即關閉返回的輸出流,在此期間它會將所有可能的剩余字節刷新到底層輸出流。關閉返回的輸出流將關閉基礎輸出流。
Base64.Decoder
提出了幾種解碼字節序列的線程安全實例方法。將空引用傳遞給以下方法之一會導致NullPointerException
:
byte[] decode(byte[] src)
:將src
所有字節解碼為新分配的字節數組,然后返回。當Base64無效時拋出IllegalArgumentException
。int decode(byte[] src, byte[] dst)
:解碼src
所有字節到dst
(從偏移量0開始)。如果dst
不足以保存解碼,或者當Base64無效的時,拋出IllegalArgumentException
。否則,返回寫入dst
的字節數。byte[] decode(String src)
:將src
所有字節解碼為新分配的字節數組,並返回該字節數組。調用此方法相當於調用decode(src.getBytes(StandardCharsets.ISO_8859_1))
。當Base64無效時拋出IllegalArgumentException
。ByteBuffer decode(ByteBuffer buffer)
:將buffer
所有字節解碼為新分配的java.nio.ByteBuffer
對象。返回后,buffer
其position將更新為它的limit; 它的limit不會改變。返回的輸出緩沖區的position將為零,其limit將是生成的解碼字節數。當Base64無效時拋出IllegalArgumentException
。在這種情況下,buffer
位置不會更新。InputStream wrap(InputStream is)
:包裝輸入流以解碼字節數據。當輸入Base64無效時,is
對象的read()
方法拋出java.io.IOException
。關閉返回的輸出流將關閉基礎輸出流。
你好,Base64
Java的Base64 API易於使用。考慮一個“Hello,World”式程序,使用Basic編碼器對Base64進行編碼,然后使用Basic解碼器對編碼文本進行Base64解碼。清單1展示了源代碼。
清單1。 HelloBase64.java
1 import java.util.Base64; 2 3 public class HelloBase64 4 { 5 public static void main(String[] args) 6 { 7 String msg = "Hello, Base64!"; 8 Base64.Encoder enc = Base64.getEncoder(); 9 byte[] encbytes = enc.encode(msg.getBytes()); 10 for (int i = 0; i < encbytes.length; i++) 11 { 12 System.out.printf("%c", (char) encbytes[i]); 13 if (i != 0 && i % 4 == 0) 14 System.out.print(' '); 15 } 16 System.out.println(); 17 Base64.Decoder dec = Base64.getDecoder(); 18 byte[] decbytes = dec.decode(encbytes); 19 System.out.println(new String(decbytes)); 20 } 21 }
編譯清單1如下:
javac HelloBase64.java
運行生成的應用程序如下:
java HelloBase64
您應該觀察以下輸出:
SGVsb G8sI EJhc 2U2N CE=
Hello, Base64!
文件編碼和解碼
Base64對編碼文件更有用。我已經創建了第二個應用程序,它演示了這個有用性以及更多的Base64 API。清單2顯示了應用程序的源代碼。
清單2。 FileEncDec.java
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.InputStream; 4 import java.io.IOException; 5 import java.io.OutputStream; 6 7 import java.util.Base64; 8 9 public class FileEncDec 10 { 11 public static void main(String[] args) 12 { 13 if (args.length != 1) 14 { 15 System.err.println("usage: java FileEncDec filename"); 16 return; 17 } 18 try (FileInputStream fis = new FileInputStream(args[0])) 19 { 20 Base64.Encoder enc1 = Base64.getEncoder(); 21 Base64.Encoder enc2 = Base64.getMimeEncoder(); 22 Base64.Encoder enc3 = Base64.getUrlEncoder(); 23 OutputStream os1 = enc1.wrap(new FileOutputStream(args[0] + "1.enc")); 24 OutputStream os2 = enc2.wrap(new FileOutputStream(args[0] + "2.enc")); 25 OutputStream os3 = enc3.wrap(new FileOutputStream(args[0] + "3.enc")); 26 int _byte; 27 while ((_byte = fis.read()) != -1) 28 { 29 os1.write(_byte); 30 os2.write(_byte); 31 os3.write(_byte); 32 } 33 os1.close(); 34 os2.close(); 35 os3.close(); 36 } 37 catch (IOException ioe) 38 { 39 System.err.printf("I/O error: %s%n", ioe.getMessage()); 40 } 41 try (FileOutputStream fos1 = new FileOutputStream("1" + args[0]); 42 FileOutputStream fos2 = new FileOutputStream("2" + args[0]); 43 FileOutputStream fos3 = new FileOutputStream("3" + args[0])) 44 { 45 Base64.Decoder dec1 = Base64.getDecoder(); 46 Base64.Decoder dec2 = Base64.getMimeDecoder(); 47 Base64.Decoder dec3 = Base64.getUrlDecoder(); 48 InputStream is1 = dec1.wrap(new FileInputStream(args[0] + "1.enc")); 49 InputStream is2 = dec2.wrap(new FileInputStream(args[0] + "2.enc")); 50 InputStream is3 = dec3.wrap(new FileInputStream(args[0] + "3.enc")); 51 int _byte; 52 while ((_byte = is1.read()) != -1) 53 fos1.write(_byte); 54 while ((_byte = is2.read()) != -1) 55 fos2.write(_byte); 56 while ((_byte = is3.read()) != -1) 57 fos3.write(_byte); 58 is1.close(); 59 is2.close(); 60 is3.close(); 61 } 62 catch (IOException ioe) 63 { 64 System.err.printf("I/O error: %s%n", ioe.getMessage()); 65 } 66 } 67 }
該FileEncDec
應用程序需要一個文件作為其孤立命令行參數的名稱。它繼續打開此文件並讀取其內容。每個讀取字節通過不同的編碼器和包裝的輸出流寫入另一個文件。之后,這些文件通過不同的解碼器和包裝的輸入流打開和讀取。結果存儲在三個單獨的文件中。
編譯清單2如下:
javac FileEncDec.java
運行生成的應用程序如下(假設一個名為JPEG的文件image.jpg
- 請參閱帖子的代碼存檔):
1 java FileEncDec image.jpg
您應該在當前目錄中觀察image.jpg1.enc
,image.jpg2.enc
和image.jpg3.enc
文件。
image.jpg1.enc
將Basic編碼存儲在一個長行上。下面是輸出的前綴,為了便於閱讀,分為兩行(...
序列表示內容未顯示):
/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/
4QM6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+...
image.jpg2.enc
將MIME編碼存儲在多行中:
/9j/4AAQSkZJRgABAQEASABIAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/ 4QM6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9 Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pg0KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpu czptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEw LzAyLzEyLTE3OjMyOjAwICAgICAgICAiPg0KCTxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3 dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+DQoJCTxyZGY6RGVzY3JpcHRpb24g cmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1s bnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJo dHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRv clRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1w LmlpZDoyMzlCQTU3RjY3RDMxMUUzODg3OEFGOTg0RUUzMkVBOSIgeG1wTU06RG9jdW1lbnRJRD0i eG1wLmRpZDoyMzlCQTU4MDY3RDMxMUUzODg3OEFGOTg0RUUzMkVBOSI+DQoJCQk8eG1wTU06RGVy aXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyMzlCQTU3RDY3RDMxMUUzODg3OEFG OTg0RUUzMkVBOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDoyMzlCQTU3RTY3RDMxMUUzODg3 OEFGOTg0RUUzMkVBOSIvPg0KCQk8L3JkZjpEZXNjcmlwdGlvbj4NCgk8L3JkZjpSREY+DQo8L3g6 eG1wbWV0YT4NCjw/eHBhY2tldCBlbmQ9J3cnPz7/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYE BAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYM CAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAAR CAAeADADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgED AwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRol JicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWW l5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3 +Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3 AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5 OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaan qKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIR AxEAPwD4y1DwrZ3epxppsxS3cfeu+HUDO5yqAnbweEDkY6k11fw4+GWqeI9JhSVdBt9Ljma6Ek9r FctNIiqTEzxgybSDGChYL+9XALMM/JegyRfEgSTb9bsWRDKRNEbhlD7WXaU5IYuMMABkkkdSOh8R RSJcxx3etaha2cajCTJ5URXLFXljPzu3mbThlYZ6Z5A7KvFNFv2cZpPzvf8AJK/3k0chqW9pKLa8 rW/Vn3t8QvFPjb4x67pOm+NNQ0O60nTLb93YWV9Nplpdg4HkzSAFlCRFkHUgBc8FiPBde8IyWuma pfXnhW6sYdPVXeaK6WO0hSRhHENzZ8xtxUfKxZuSc5BHz78NfjD4m8D+L9S1nSbfxprV5q0TLqd3 aRzNLewuypyXyZkO9sIE2rsU4GMjd+HXizVPhemq3Xh61+L1zHrbLpl3LcaVt8uzYoGkBKs8bqD8 skfzFN4Kxh+eT/Wilhnytp7bJ2v1Wj0b8/yR1f2DOurxut92vlvul5H0xofxB8Eaf8HZobj4c6dp uqarp8unwa3DK97I43qXxHK5SKbB/wBafmCnCAKeOB8Pado91dTxpazpBJC6nMMV3M4xyFZ02xnq fMVdy449R4V8X/E0PhT4kRtZ2Xju+tlhMUE0OoJHLDKjgMojKbGiMSbxlVGSoyONvK3H7Rnia90O 2l0OG8WeztVW5kJE7pN5SLvXAHLSuxbhjwNuxQRV4XiqlVp+0hCXvaq7Xyvdt+W2+yM8Vw/UpT5J zj7ujsn+iS8/zZ+h91qGi3t7Lpsmi3CR+SLi3+y3kkIjTgZYBDhlG7bxkZPLFhWh47+EmgzeDdQ8 UeEdYbTdPUL9p0xtUuJyJtuxWEsbxnBOThwuArAsVznFstCaLxjpuk7bdYLi5+ybQhYIpcxEg8cj jHsPUkn16Pwf/wAIHqL2d5cR6ppdx+7Wze2CQuihTyqsNh28gglg3RgBz+FYOpDBzi5RUodU0ndd d1v1Wq1P0DETnibtVGpdNWrfd/wT520DRfEV1eyWt3cXek/2ZCF3Tt9str8RxKCVZozI0rKFwC6Y L84GBUC+GfE2sQ6nNc3Gl6T/AGezSodT0mOX7RIxxGEEbqFkxuHqSVXJJBEn7YNvJ8Dvit9ttbi+ uNH1WITC3FwI7i33gSbFYJt2j7v3eRk4ycjwo/F6bTPOjT7bI0gJLtPy+75lDDoccE+9fquG4Syv F044mnTSUkmrJrR+V/0PjqnE2OoN0ZTbs3e7PbdHbXtGvlSbS/Ccmm3Nq7/aLN73TWluFXhgD5q5 BZeuMbQAVANN8feJYfBuoLqFj4L1jUrW1t45ZpV8SIJbNiqyNuD5Dqm6TDA/KcggEYrF8M/FTQ9c +HurfZLfV7jVNJ0sag320oIBH5yqyoUbcrfMT6HnIGa53Qvi9b+WGkspp47hWQo7jKj2YflyDkVn /qPgJXlFyT23dvuTX5ov/WrGxsna3or/AHtM/9k=
image.jpg3.enc
將URL和文件名安全編碼存儲在一個長行上。下面是輸出的前綴,分為兩行以便於閱讀:
_9j_4AAQSkZJRgABAQEASABIAAD_4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD_
4QM6aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu-...
image.jpg1.enc
和image.jpg3.enc
之間的區別在於每個/
都被替換為 _
並且每個+
都被替換為 -
。
您還應該在當前目錄中觀察1image.jpg
,2image.jpg
和3image.jpg
文件。這些文件中的每一個都包含相同的內容image.jpg
。
結論
Base64 API是Java 8引入的各種小“寶石”之一。如果你必須使用Base64,你會發現這個API非常方便。我鼓勵您嘗試一下Base64
,從本文未涉及的方法開始。