Base64 的原理、實(shí)現(xiàn)及應(yīng)用

Base64編碼是基于64個(gè)字符(字符分別為:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxzy0123456789+/)的編碼方式,因?yàn)?的6次方正好為64,所以我們用6bit就可以表示出64個(gè)字符,eg:000000對(duì)應(yīng)'A',000001對(duì)應(yīng)'B',111111對(duì)應(yīng)'/'。
轉(zhuǎn)換表如下:


QQ截圖20160411092432.png

按我們的習(xí)慣,8bit是1個(gè)字節(jié),所以我們正常使用的時(shí)候,一般都是1Byte=8bit(字符'a'=97=01100001)來(lái)使用。所以我們處理字符串的時(shí)候會(huì)遇到8bit/16bit/24bit/32bit……的情況,而B(niǎo)ase64按照6bit為一個(gè)單元,處理的時(shí)候會(huì)遇到6bit/12bit/18bit/24bit/30bit……的情況,8和6的最小公倍數(shù)是24,所以我們用1、2、3個(gè)正常字符這三種情況就可以把所有需要轉(zhuǎn)換成Base64的字符串概括了。

  • 被3整除個(gè)字符(3/6/9/12……):abc=01100001 01100010 01100011 分成Base64分組后為:011000 010110 001001 100011 即24 22 9 35,對(duì)應(yīng)Base64編碼的 YWJj
  • 除3余1個(gè)字符(2/5/8/11……):ab=01100001 01100010,分成Base64分組后為:011000 010110 0010,0010不夠6bit,需要補(bǔ)0為:001000,得到Y(jié)WI,因?yàn)?個(gè)Base編碼為一組,最后再補(bǔ)上'='補(bǔ)齊一組,即:YWI=
  • 除3余2個(gè)字符(1/4/7/10……):a=011000010,分成Base64分組后為:011000 01,01不夠6bit,需要補(bǔ)0為:010000,得到Y(jié)Q,因?yàn)?個(gè)Base編碼為一組,最后再補(bǔ)上'='補(bǔ)齊一組,即:YQ==

上面的文字歸結(jié)為下圖:

QQ截圖20160411094646.png

可以看出,所有轉(zhuǎn)換后的Base64編碼都是4個(gè)字符的倍數(shù)(4/8/12/16……),如果不夠4個(gè)字符的,都用'='填充了。

/**
 * <p>Base64編碼是基于64個(gè)字符(字符分別為:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxzy0123456789+/)的編碼方式,
 * 因?yàn)?的6次方正好為64,所以我們用6bit就可以表示出64個(gè)字符,eg:000000對(duì)應(yīng)A,000001對(duì)應(yīng)B</p>
 * <p>按我們的習(xí)慣,一般都是1Byte=8bit(字符'a'=97=01100001)的使用,所以我們可以用24bit(6和8的最小公倍數(shù))來(lái)進(jìn)行分組,24正好事3BYTE,可以分出4組Base64的分組,需要編碼的字符串有如下情況:
 * <li>被3整除:abc=01100001 01100010 01100011 分成Base64分組后為:011000 010110 001001 100011 即24 22 9 35,對(duì)應(yīng)Base64編碼的 YWJj</li>
 * <li>除3余1:ab=01100001 01100010,分成Base64分組后為:011000 010110 0010,0010不夠6bit,需要補(bǔ)0為:001000,得到Y(jié)WI,因?yàn)?個(gè)Base編碼為一組,最后再補(bǔ)上'='補(bǔ)齊一組,即:YWI=</li>
 * <li>除3余2:a=011000010,分成Base64分組后為:011000 01,01不夠6bit,需要補(bǔ)0為:010000,得到Y(jié)Q,因?yàn)?個(gè)Base編碼為一組,最后再補(bǔ)上'='補(bǔ)齊一組,即:YQ==</li>
 * </p>
 * @author chmod400
 *
 */
public class Base64Utils {
    
    private static String codeStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxzy0123456789+/";
    private static char[] code = codeStr.toCharArray();
    
    /**
     * 對(duì)字符串進(jìn)行Base64編碼
     * @param str
     * @return
     */
    public static String encode(String str) {
        if(str == null) {
            throw new NullPointerException();
        }
        StringBuffer result = new StringBuffer();
        // 字符串轉(zhuǎn)為二進(jìn)制
        String binStr = str2Bin(str);
        // 6bit 為一個(gè)單元,需要補(bǔ)0的位數(shù)
        int tail = binStr.length() % 6;
        if(tail != 0) {//最后剩2bit,需要補(bǔ)4位,剩4位需要補(bǔ)2bit
            tail = 6 - tail;
        }
        for(int i = 0; i < tail; i++) {
            binStr += "0";
        }
        for(int i = 0; i < binStr.length() / 6; i++) {
            int beginIndex = i * 6;
            String s = binStr.substring(beginIndex, beginIndex+6);
            // 二進(jìn)制轉(zhuǎn)十進(jìn)制
            int codePoint = Integer.valueOf(s, 2);
            // 對(duì)應(yīng)的字符
            char c = code[codePoint];
            result.append(c);
        }
        // 需要補(bǔ)=的位數(shù)
        int groupNum = binStr.length() / 6;// 6bit為一組
        if((groupNum % 4) != 0) {
            tail = 4 - groupNum % 4;
        }
        for(int i = 0; i < tail; i++) {
            result.append("=");
        }
        return result.toString();
    }

    /**
     * base64解碼
     * @param str
     * @return
     */
    public static String decode(String str) {
        if(str == null) {
            throw new NullPointerException();
        }
        StringBuffer result =  new StringBuffer();
        // 去除末尾的'='
        int index = str.indexOf("=");
        if (index >= 0) {
            str = str.substring(0, index);
        }
        // base64字符串轉(zhuǎn)換為二進(jìn)制
        String binStr = base64Str2Bin(str);
        // 將二進(jìn)制按8bit一組還原成原字符
        for(int i = 0; i < binStr.length() / 8; i++) {
            int beginIndex = i * 8;
            String s = binStr.substring(beginIndex, beginIndex+8);
            String c = bin2Str(s);
            result.append(c);
        }
        return result.toString();
    }
    
    /**
     * 字符串轉(zhuǎn)換為二進(jìn)制字符串
     * @param str
     * @return
     */
    private static String str2Bin(String str) {
        StringBuffer sb = new StringBuffer();
        // 字符串轉(zhuǎn)為字符數(shù)組
        char[] c = str.toCharArray();
        for(int i = 0; i < c.length; i++) {
            // 將每個(gè)字符轉(zhuǎn)換為二進(jìn)制
            String s = Integer.toBinaryString(c[i]);
            // 需要補(bǔ)0的長(zhǎng)度
            int len = 8 - s.length();
            for(int j = 0; j < len; j++) {
                s = "0" + s;
            }
            sb.append(s);
        }
        return sb.toString();
    }
    
    /**
     * Base64字符串轉(zhuǎn)換為二進(jìn)制字符串
     * @param str
     * @return
     */
    private static String base64Str2Bin(String str) {
        StringBuffer sb = new StringBuffer();
        // 字符串轉(zhuǎn)為字符數(shù)組
        char[] c = str.toCharArray();
        for(int i = 0; i < c.length; i++) {
            // 將每個(gè)字符轉(zhuǎn)換為二進(jìn)制
            int index = codeStr.indexOf(c[i]);
            String s = Integer.toBinaryString(index);
            // 需要補(bǔ)0的長(zhǎng)度
            int len = 6 - s.length();
            for(int j = 0; j < len; j++) {
                s = "0" + s;
            }
            sb.append(s);
        }
        return sb.toString();
    }
    
    /**
     * 二進(jìn)制轉(zhuǎn)換為字符串
     * @param binStr
     * @return
     */
    private static String bin2Str(String binStr) {
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < binStr.length() / 8; i++) {
            int beginIndex = i * 8;
            String s = binStr.substring(beginIndex, beginIndex+8);
            // 二進(jìn)制轉(zhuǎn)十進(jìn)制
            int codePoint = Integer.valueOf(s, 2);
            // 對(duì)應(yīng)的字符
            char c = Character.toChars(codePoint)[0];
            sb.append(c);
        }
        return sb.toString();
    }
    
    public static void main(String[] args) {
        System.out.println(str2Bin("ab"));
//      System.out.println(bin2Str("000001000001000001000000"));
        /*System.out.println(encode("a"));
        System.out.println(encode("ab"));
        System.out.println(encode("abc"));
        System.out.println(encode(""));
        System.out.println(encode(null));*/
        
//      System.out.println(encode(codeStr));
        
        System.out.println(decode("YQ=="));
        System.out.println(decode("YWI="));
        System.out.println(decode("YWJj"));
        System.out.println(decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJydHV2d3h6eTAxMjM0NTY3ODkrLw=="));
        System.out.println(decode(""));
        System.out.println(decode(null));
    }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 什么是Base64 Base64是一種基于64個(gè)可打印字符來(lái)表示二進(jìn)制數(shù)據(jù)的表示方法 Base64是一種編碼...
    理查德成閱讀 3,049評(píng)論 0 2
  • 加密就是為了安全通信而誕生的。沒(méi)有通信,加密也沒(méi)有太大存在的意義。 雖說(shuō)Base64算不上一種加密,只是一種具有固...
    王韓峰閱讀 1,089評(píng)論 0 3
  • 0x01 目錄 常見(jiàn)編碼: ASCII編碼 Base64/32/16編碼 shellcode編碼 Quoted-p...
    H0f_9閱讀 13,482評(píng)論 2 17
  • 1、Base64編碼原理 下圖為Base64編碼索引表: 字符選用了"A-Z、a-z、0-9、+、/" 64個(gè)可打...
    M_JCs閱讀 1,876評(píng)論 1 9
  • ** Base64用于將二進(jìn)制數(shù)據(jù)編碼成ASCII字符 ** (圖片、文件等都可轉(zhuǎn)化為二進(jìn)制數(shù)據(jù))傳輸信道只支持A...
    峰峰小閱讀 4,866評(píng)論 0 0

友情鏈接更多精彩內(nèi)容