Java 8 初探 - Base64

閱讀時間約 5 分鐘
此為過去的舊文,2014 年 5 月 11 日初次發表於 logdown。

這次看一個比較小的東西,就是 Java 8終於將 Base64 編解碼器內建到 java.util 套件中了。Base64 雖然會增加實際傳輸資料的長度,但在只用文字的網路協定中傳輸 binary 資料時常常用到 (例如:MIME email),所以一直到 Java 8 才內建確實讓人意外,在 Java 8 之前,需要 Base64 編解碼器,都需要透過第三方函式庫,例如 Apache Commons Codec

還記得之前某個工作內容是當使用者透過瀏覽器上傳 A 檔案到 X 系統時,因某些原故,X 系統不提供檔案儲放的功能,實際上是將該檔案 A 放到另一個有提供檔案內容檢索的 Y 系統;另一個類似的情況是,當使用者透過瀏覽器在 X 系統下載 B 檔案(內容是機器生成的)時,該檔案 B 會放到 Y 系統的另一個資料夾中備查。X 系統與 Y 系統都是標準的 RESTful Web Service,當時,X 和 Y 系統間檔案內容就是先以 Base64 編碼後,以文字的方式夾帶在 JSON 中透過 HTTP 傳輸。當時用的 Base64 編解碼器正是 Apache Commons Codec。

既然 Java 8 內建 Base64 編解碼器,那就來寫點程式試用看看吧!不過個人的習慣,對於從輸入讀取資料放到輸出這種事,喜歡使用 Apache Commons IOIOUils.copy(InputStream, OutputStream) 函式,不過如果沒有使用 Apache Commons IO,也可以自己寫一個,之後就可以不用再寫 while loop 做資料讀取複製的程式了。


有了輔助函式後,就先使用編碼器,將一個 InputStream 的資料用 Base64 編碼器編碼後放到指定的 OutputStream,下例中,encode(InputStream, OutputStream, Base64.Encoder) 函式接受三個參數,第一個是代表資料的來源,第二個是代表編碼後資料的目的地,這兩個蠻容易理解的,那第三個呢?為什麼還要指定編碼器?難道 Base64 編碼有不同種類嗎?是的,Base64 在不同通訊協定中有些變形,所以 Java 8 提供三種 Base64 的編解碼器。

第一種是基本版 (分別用 Base64.getEncoder()Base64.getDecoder() 取得編解碼器),只用 0-9a-zA-Z+/= 字元編碼且內容不換行;第二種針對網址和檔名修改的版本 (用Base64.getUrlEncoder()Base64.getUrlDecoder() 取得編解碼器),由於 +/ 符號在網址中有特殊用途,某些檔案系統也不允許 / 作為檔名,所以第二種用 - (減號) 取代 +,用 _ (底線) 取代/;第三種針對 MIME 調整的版本 (用 Base64.getMimeEncoder()Base64.getMimeDecoder() 取得編解碼器),使用的編碼字元和第一種一樣,但每輸出76個字元會加上一組 \r\n 換行。假設第一種是比較常用的情況,是可以如下例那樣寫一個無第三參數的版本方便使用。


編碼後就可以用解碼器進行解碼的動作,下例中 decode(InputStream, OutputStream, Base64.Decoder) 同樣接受三個參數,第一個參數是待解碼的資料來源,第二個是解碼後的資料目的地,第三個是解碼器。剛提到的三種不同編解碼器是無法混用的,所以使用第一種編碼器編碼的內容一定要用第一種解碼器來進行解碼。同樣,也可以提共一個無第三參數的版本方便使用,接下來的範例程式都可以用同樣的方法提供一個預先使用第一種編解碼器的版本。


有了從 InputStream 讀取資料進行編碼或解碼動作後放到 OutputStream 的函式後,就可以來點不一樣的變形了,例如像下例,可以指定輸入的檔案和輸出的檔案,利用 FileInputStreamFileOutputStream將檔案包裝成串流來使用,這時就可以使用上面提供的 encodedecode 函示來進行編解碼的動作。


當然,很多時候編解碼後的內容並不是要放到檔案中,以剛剛提到的例子,檔案內容會先被編碼,然後當成 JSON 的一部分,這時會希望有類似的程式,將編解碼後的內容當成字串,這時可以用 ByteArrayOutputStream 暫時存放編解碼後的內容,然後使用 toString(String) 將結果以字串輸出。


同樣,需要被編解碼的資料來源不一定是從檔案來,可能就是個字串,這時下面的函式就幫得上忙了,先用 getBytes() 取得字串的位元組陣列,接著用 ByteArrayInputStream 將位元組陣列包裝成輸入串流,然後用同樣的方法,對輸入的字串進行編解碼的動作。


Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包,對~前提是要有 Java 8 的環境,變成用不用內建的 Base64 編解碼器又是一種抉擇了。

52會員
102內容數
這是從 Medium 開始的一個專題,主要是想用輕鬆閒談的方式,分享這幾年軟體開發的心得,原本比較侷限於軟體架構,但這幾年的文章不僅限於架構,也聊不少流程相關的心得,所以趁換平台,順勢換成閒談軟體設計。
留言0
查看全部
發表第一個留言支持創作者!
Spirit的沙龍 的其他內容
書摘《高品質微服務》
閱讀時間約 11 分鐘
Java 8 初探 - Lambda
閱讀時間約 6 分鐘
Java 8 初探 - Closure
閱讀時間約 5 分鐘
Java 8 初探 - Stream
閱讀時間約 7 分鐘
Java 8 初探 - Default Methods
閱讀時間約 5 分鐘
你可能也想看
【Java】SpringBoot 專案初始建置學習Spring Boot是Java工程師必備技能,文章分享瞭如何自學並快速上手Spring Boot開發,包括架構、開發工具、專案建立以及實作過程。
Thumbnail
avatar
2024-03-24
JAVA 呼叫 LINE NOTIFY 發訊息給群組本文章將介紹如何在LINE Notify上設定及使用權杖(access token)來進行通知功能。透過此API,可以使用curl或JAVA CODE來讓結果顯示在Line上面,達到及時的通知效果。
Thumbnail
avatar
艾倫の旅遊日誌 | 趴趴走找美食 | 心情寫照
2024-03-01
Java 不支持multi-inheritanceJava不能同時多重繼承 但是可以多層繼承
avatar
Genos's Coding Diary
2023-09-20
Java寫一次,到處執行WORA, Write Once Run Anywhere Java 不依賴於任何平台,Java可以在任何平台上執行,前提是那平台上要有安裝JVM Java的執行流程
Thumbnail
avatar
Genos's Coding Diary
2023-09-17
Java Development Kit (JDK)下載完JDK之後,在本機的環境變數中加入此JDK的bin路徑以便系統能識別使用 javac 是java compiler
Thumbnail
avatar
Genos's Coding Diary
2023-09-17
【Java】建立Maven專案使用第三方套件 相信很多初學者學python的原因,不外乎語法簡單、好上手、重點是有很多現成的套件可以玩。那麼,Java呢?有!當然有!而且還多到你不知道該選哪個好! 今天的文章主要示範如何在vscode新建立Java 的maven專案,並且透過maven安裝這些額外的套件(依賴)
Thumbnail
avatar
2023-09-02
【Java】安裝開始、開發環境建立 最近配合公司政策換了新電腦,重新回想起從頭建環境的惡夢。本篇文就來記錄一下如何開始踏入Java的第一步,方便起見也使用相對Eclipse、IntelliJ來說輕量不少的VScode作為編輯器。
Thumbnail
avatar
2023-07-05
Java Script自學經驗回顧來到學期2-3的階段,第一個作業就是打造餐廳清單。原本認為經過電影清單的學習經歷之後,對於打造餐廳清單應該也不會太過困難;沒想到我花了2個月的時間才把作業完整交出去。 在寫餐廳清單的初期,第一個碰到的問題就是首頁無法秀出餐廳評分這個選項。我試著參考其他同學的作品也改了版面的設計,卻始終無法出現餐廳評
avatar
奧莉薇
2023-02-28
Java Bird Coffee|通化街六張犁商圈,小巧而溫馨禾雀咖啡工作室位在通化街尾端,靠近六張犁的禾雀咖啡工作室,質樸的感覺是一家適合假日早晨來待上好一會兒的好去處。 主打自家烘培手沖及義式咖啡,最大特色還有自家製的麵包、甜點輕食,最喜歡吃的莫過於他們的鮮奶吐司。曾經住在這裡好長一段時間,週末去搶個一包可以在家裡烤來吃,是相當幸福的感覺。 冰羅馬咖啡則是我喝過最喜歡的
Thumbnail
avatar
Celine 寫在這裡
2023-02-06
Java abstract class 與 interface 的差別abstract class = 抽象類別 interface = 介面 抽象類別與介面都無法建立物件。 1. 使用abstract關鍵字來建立抽象類別,interface關鍵字建立介面。 interface只能繼承interface,且可以繼承多個:
Thumbnail
avatar
Vic Lin
2022-07-04