[Java技術(shù) | 細(xì)談 Java 8 中的 Base64]

轉(zhuǎn)載Java技術(shù) | 細(xì)談 Java 8 中的 Base64

閱讀目錄(Content)

回到頂部(go to top)

簡要了解

Base 64是一種使64個(gè)字符來表示任意二進(jìn)制數(shù)據(jù)的方法震缭。Base 64是一種非常常用的二進(jìn)制編解碼方案嘶窄。

有些說法是說哭廉,使用Base 64作為加密解密的功能脊僚,比如一個(gè)Web系統(tǒng)中,密碼字段存入數(shù)據(jù)庫的時(shí)候使用Base64.encode一下,其實(shí)Base 64的編碼辽幌、解碼方法都是簡單公開的增淹,用以加密、解密實(shí)在談不上啥保障性乌企。

在Java 8中虑润,整合了Base 64。Java 8 為開發(fā)者提供了 java.util.Base64 的工具類加酵,Java 8現(xiàn)在有內(nèi)置編碼器和解碼器的Base 64編碼拳喻。在Java 8中有三種類型的Base 64編碼。

第一種猪腕,簡單Base 64

Basic 編碼是標(biāo)準(zhǔn)的Base 64編碼冗澈,用于處理常規(guī)的需求:輸出的內(nèi)容不添加換行符,而且輸出的內(nèi)容由64個(gè)基本字符組成陋葡。

輸出映射設(shè)置字符在A-ZA-Z0-9+/亚亲。編碼器不添加任何換行輸出和解碼器拒絕在A-Za-z0-9+/以外的任何字符。

第二種腐缤,URL編碼

輸出映射設(shè)置字符在A-Za-z0-9-_捌归。輸出URL和文件名安全。由于標(biāo)準(zhǔn)的Basic編碼可能會(huì)出現(xiàn)+/ ,在URL中就不能直接作為參數(shù)岭粤,所以又有一種“url safe” 的Base 64編碼惜索,其實(shí)就是吧字符+/分別變成-_

在這里插入圖片描述

第三種剃浇,MIME編碼

輸出映射到MIME友好的格式巾兆。輸出表示在每次不超過76個(gè)字符行和使用'\r'后跟一個(gè)換行符'\n'回車作為行分隔符。無行隔板的存在是為了使編碼的結(jié)束輸出偿渡。MIME(Multipurpose Internet Mail Extensions)多用途互聯(lián)網(wǎng)郵件擴(kuò)展類型。是設(shè)定某種擴(kuò)展名的文件用對(duì)應(yīng)的應(yīng)用程序來打開的方式類型霸奕。

它是一種互聯(lián)網(wǎng)標(biāo)準(zhǔn)溜宽,擴(kuò)展了電子郵件標(biāo)準(zhǔn),使其可以支持:非ASCII字符文本质帅;非文本格式附件(二進(jìn)制适揉、聲音、圖像等)煤惩;由多部分組成的消息體嫉嘀;包含非ASCII字符的頭信息等。

舉個(gè)栗子:右鍵中有一個(gè)Word附件(二進(jìn)制文件)魄揉,點(diǎn)擊預(yù)覽剪侮,瀏覽器會(huì)直接打開Office。可以理解為MIME設(shè)定了這種對(duì)應(yīng)關(guān)系瓣俯。

MIME編碼器會(huì)使用基本的字母數(shù)字產(chǎn)生Base 64輸出杰标,而且對(duì)MIME格式友好:每一行輸出不超過76個(gè)字符,而且每行以“\r\n”符結(jié)束彩匕。

回到頂部(go to top)

實(shí)用API與代碼示例

API

Base 64類

序號(hào) 方法 描述
1 Base64.getEncoder() 返回一個(gè) Base64.Encoder 腔剂,編碼使用基本型 base64 編碼方案
2 Base64.getDecoder() 返回一個(gè) Base64.Decoder ,解碼使用基本型 base64 編碼方案
3 Base64. getUrlEncoder() 返回一個(gè) Base64.Encoder 驼仪,編碼使用 URL 和文件名安全型 base64 編碼方案
4 Base64.getUrlDecoder() 返回一個(gè) Base64.Decoder 掸犬,解碼使用 URL 和文件名安全型 base64 編碼方案。
5 Base64.getMimeEncoder() 返回一個(gè) Base64.Encoder 绪爸,編碼使用 MIME 型 base64 編碼方案湾碎。
6 Base64.getMimeEncoder(int lineLength, byte[] lineSeparator) 返回一個(gè) Base64.Encoder ,編碼使用 MIME 型 base64 編碼方案毡泻,可以通過參數(shù)指定每行的長度及行的分隔符胜茧。
7 Base64.getMimeDecoder() 返回一個(gè) Base64.Decoder ,解碼使用 MIME 型 base64 編碼方案仇味。

內(nèi)嵌類Encoder

序號(hào) 方法名 描述
1 byte[] encode(byte[] src) 編碼呻顽,返回一個(gè)byte數(shù)組
2 int encode(byte[] src, byte[] dst) 編碼,寫進(jìn)新的byte數(shù)組
3 String encodeToString(byte[] src) 編碼丹墨,返回一個(gè)字符串
4 ByteBuffer encode(ByteBuffer buffer) 編碼
5 OutputStream wrap(OutputStream os) 編碼
6 Encoder withoutPadding() 編碼

內(nèi)嵌類Decoder

序號(hào) 方法名 描述
1 byte[] decode(byte[] src) 解碼廊遍,返回一個(gè)byte數(shù)組,入?yún)閎yte數(shù)組
2 byte[] decode(String src) 解碼贩挣,返回一個(gè)byte數(shù)組喉前,入?yún)樽址?/td>
3 int decode(byte[] src, byte[] dst) 解碼
4 ByteBuffer decode(ByteBuffer buffer) 解碼
5 InputStream wrap(InputStream is) 解碼

代碼示例

package com.kjgym.common.java8;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author kjgym
 * @description Demo for Java8's Base64
 * @date 2019/9/17 11:25
 */
public class Java8Base642 {

    public static void main(String[] args) {
        final String demoStr = "kjgym";
        final byte[] strByte = demoStr.getBytes(StandardCharsets.UTF_8);

        // 基本型編碼方案
        String s = Base64.getEncoder().encodeToString(strByte);
        System.out.println("基本編碼: " + s);
        String ss = new String(Base64.getDecoder().decode(s));
        System.out.println("解碼: " + ss);

        // 使用 URL 和文件名安全型 base64 編碼方案。
        String s1 = Base64.getEncoder().encodeToString(strByte);
        System.out.println("URL編碼: " + s1);
        String ss1 = new String(Base64.getUrlDecoder().decode(s));
        System.out.println("解碼: " + ss1);

        // 使用 MIME 型 base64 編碼方案
        String s2 = Base64.getMimeEncoder().encodeToString(strByte);
        System.out.println("MIME編碼: " + s2);
        String ss2 = new String(Base64.getMimeDecoder().decode(s));
        System.out.println("解碼: " + ss2);

    }
}

結(jié)果:

基本編碼: a2pneW0=
解碼: kjgym
URL編碼: a2pneW0=
解碼: kjgym
MIME編碼: a2pneW0=
解碼: kjgym

回到頂部(go to top)

閱讀源碼

  1. 先來總體看一下Base 類王财,該類主要包含兩個(gè)內(nèi)嵌類EncoderDecoder以及七個(gè)構(gòu)造內(nèi)嵌類的方法:
在這里插入圖片描述
  1. 再看兩個(gè)內(nèi)嵌類卵迂。比如Encoder(部分源代碼):

    public static class Encoder {
    
            private final byte[] newline;
            private final int linemax;
            private final boolean isURL;
            private final boolean doPadding;
    
            private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding {
                this.isURL = isURL;
                this.newline = newline;
                this.linemax = linemax;
                this.doPadding = doPadding;
            }
    
            static final Encoder RFC4648 = new Encoder(false, null, -1, true);
            static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
            static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
    
            public byte[] encode(byte[] src) {}
    
            public int encode(byte[] src, byte[] dst) {}
    
            @SuppressWarnings("deprecation")
            public String encodeToString(byte[] src) {}
    
            public ByteBuffer encode(ByteBuffer buffer) {}
    
            public OutputStream wrap(OutputStream os) {}
    
            public Encoder withoutPadding() {}
    
            private int encode0(byte[] src, int off, int end, byte[] dst) {}
        }
    

    構(gòu)造器私有化,對(duì)外提供單個(gè)靜態(tài)對(duì)象绒净,然后在Base 64類中见咒,使用getEncoder的方式愛調(diào)用,使用了單例模式挂疆。

    static final Encoder RFC4648 = new Encoder(false, null, -1, true);
    static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
    static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
    
  2. Decoder與上文Encoder相似改览,這里不再贅述。有興趣自己Ctrl + 單擊去看源碼缤言。

回到頂部(go to top)

拓展

  1. StandardCharsets類宝当。在java.nio.charset包下的一個(gè)類,在字符串和byte數(shù)組相互轉(zhuǎn)換需要制定編碼的時(shí)候使用胆萧。該類有六種編碼格式:

    /*
     * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     */
    package java.nio.charset;
    
    /**
     * Constant definitions for the standard {@link Charset Charsets}. These
     * charsets are guaranteed to be available on every implementation of the Java
     * platform.
     *
     * @see <a href="Charset#standard">Standard Charsets</a>
     * @since 1.7
     */
    public final class StandardCharsets {
    
        private StandardCharsets() {
            throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
        }
        /**
         * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
         * Unicode character set
         */
        public static final Charset US_ASCII = Charset.forName("US-ASCII");
        /**
         * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
         */
        public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
        /**
         * Eight-bit UCS Transformation Format
         */
        public static final Charset UTF_8 = Charset.forName("UTF-8");
        /**
         * Sixteen-bit UCS Transformation Format, big-endian byte order
         */
        public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
        /**
         * Sixteen-bit UCS Transformation Format, little-endian byte order
         */
        public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
        /**
         * Sixteen-bit UCS Transformation Format, byte order identified by an
         * optional byte-order mark
         */
        public static final Charset UTF_16 = Charset.forName("UTF-16");
    }
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末庆揩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盾鳞,老刑警劉巖犬性,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異腾仅,居然都是意外死亡乒裆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門推励,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹤耍,“玉大人,你說我怎么就攤上這事验辞「寤疲” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵跌造,是天一觀的道長杆怕。 經(jīng)常有香客問我,道長壳贪,這世上最難降的妖魔是什么陵珍? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮违施,結(jié)果婚禮上互纯,老公的妹妹穿的比我還像新娘。我一直安慰自己磕蒲,他們只是感情好留潦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辣往,像睡著了一般兔院。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上站削,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天坊萝,我揣著相機(jī)與錄音,去河邊找鬼钻哩。 笑死屹堰,一個(gè)胖子當(dāng)著我的面吹牛肛冶,可吹牛的內(nèi)容都是我干的街氢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼睦袖,長吁一口氣:“原來是場噩夢啊……” “哼珊肃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤伦乔,失蹤者是張志新(化名)和其女友劉穎厉亏,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烈和,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡爱只,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了招刹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恬试。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疯暑,靈堂內(nèi)的尸體忽然破棺而出训柴,到底是詐尸還是另有隱情,我是刑警寧澤妇拯,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布幻馁,位于F島的核電站,受9級(jí)特大地震影響越锈,放射性物質(zhì)發(fā)生泄漏仗嗦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一瞪浸、第九天 我趴在偏房一處隱蔽的房頂上張望儒将。 院中可真熱鬧,春花似錦对蒲、人聲如沸钩蚊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砰逻。三九已至,卻和暖如春泛鸟,著一層夾襖步出監(jiān)牢的瞬間蝠咆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工北滥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刚操,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓再芋,卻偏偏與公主長得像菊霜,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子济赎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容