此為過去的舊文,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 IO 的 IOUils.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-9
、a-z
、A-Z
、+
、/
和 =
字元編碼且內容不換行;第二種針對網址和檔名修改的版本 (用Base64.getUrlEncoder()
和 Base64.getUrlDecoder()
取得編解碼器),由於 +
和 /
符號在網址中有特殊用途,某些檔案系統也不允許 /
作為檔名,所以第二種用 -
(減號) 取代 +
,用 _
(底線) 取代/
;第三種針對 MIME 調整的版本 (用 Base64.getMimeEncoder()
和 Base64.getMimeDecoder()
取得編解碼器),使用的編碼字元和第一種一樣,但每輸出76個字元會加上一組 \r\n
換行。假設第一種是比較常用的情況,是可以如下例那樣寫一個無第三參數的版本方便使用。
編碼後就可以用解碼器進行解碼的動作,下例中 decode(InputStream, OutputStream, Base64.Decoder)
同樣接受三個參數,第一個參數是待解碼的資料來源,第二個是解碼後的資料目的地,第三個是解碼器。剛提到的三種不同編解碼器是無法混用的,所以使用第一種編碼器編碼的內容一定要用第一種解碼器來進行解碼。同樣,也可以提共一個無第三參數的版本方便使用,接下來的範例程式都可以用同樣的方法提供一個預先使用第一種編解碼器的版本。
有了從 InputStream
讀取資料進行編碼或解碼動作後放到 OutputStream
的函式後,就可以來點不一樣的變形了,例如像下例,可以指定輸入的檔案和輸出的檔案,利用 FileInputStream
和 FileOutputStream
將檔案包裝成串流來使用,這時就可以使用上面提供的 encode
和 decode
函示來進行編解碼的動作。
當然,很多時候編解碼後的內容並不是要放到檔案中,以剛剛提到的例子,檔案內容會先被編碼,然後當成 JSON 的一部分,這時會希望有類似的程式,將編解碼後的內容當成字串,這時可以用 ByteArrayOutputStream
暫時存放編解碼後的內容,然後使用 toString(String)
將結果以字串輸出。
同樣,需要被編解碼的資料來源不一定是從檔案來,可能就是個字串,這時下面的函式就幫得上忙了,先用 getBytes()
取得字串的位元組陣列,接著用 ByteArrayInputStream
將位元組陣列包裝成輸入串流,然後用同樣的方法,對輸入的字串進行編解碼的動作。
Java 8 有了 Base64 編解碼器,方便不少,不過 Apache Commons Codec 提供更多常用的編解碼器,其實是更方便的,但如果你的應用程式中只需要 Base64 編解碼器,在有 Java 8 的環境中確實不需要將 Apache Commons Codec 和專案一起打包,對~前提是要有 Java 8 的環境,變成用不用內建的 Base64 編解碼器又是一種抉擇了。