我的Java开发学习之旅------>Base64的编码思想以及Java实现

来源:互联网 发布:excel统计分析软件 编辑:程序博客网 时间:2024/06/18 18:25

Base64是一种用64个字符来表示任意二进制数据的方法。

用记事本打开exe、jpg、pdf这些文件时,我们都会看到一大堆乱码,因为二进制文件包含很多无法显示和打印的字符,所以,如果要让记事本这样的文本处理软件能处理二进制数据,就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。


一、编码规则

所谓Base64,就是说选出64个字符----小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)----作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

具体来说,转换方式可以分为四步。

  • 第一步,将每三个字节作为一组,一共是24个二进制位。
  • 第二步,将这24个二进制位分为四组,每个组有6个二进制位。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
  • 第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。

注:BASE64字符表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/



Base64 编码表ValueChar
ValueChar
ValueChar
ValueChar0A16Q32g48w1B17R33h49x2C18S34i50y3D19T35j51z4E20U36k5205F21V37l5316G22W38m5427H23X39n5538I24Y40o5649J25Z41p57510K26a42q58611L27b43r59712M28c44s60813N29d45t61914O30e46u62+15P31f47v63/



因为,Base64将三个字节转化成四个字节,所以Base64编码后的文本,会比原文本大出三分之一左右。


举一个具体的实例,演示英语单词Man如何转成Base64编码。

文本ManASCII编码7797110二进制位010011010110000101101110索引1922546Base64编码TWFu

  • 第一步,"M"、"a"、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。
  • 第二步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。
  • 第四步,根据上表,得到每个值对应Base64编码,即T、W、F、u。

因此,Man的Base64编码就是TWFu。


我们看看另外不是刚好是3个字节的情况! 

文本(1 Byte)A

二进制位01000001















二进制位(补0)010000010000











Base64编码QQ==文本(2 Byte)BC
二进制位0100001001000011

xxxxxx二进制位(补0)010000100100001100xxxxxxBase64编码QkM =

因此,A的Base64编码就是QQ==,BC的Base64编码就是QkM=


 

二、解码规则

      解码过程就是把4个字节再还原成3个字节再根据不同的数据形式把字节数组重新整理成数据。

三、Java实现Base64

public class Base64Utils {/** * 将一个字节数组转换成base64的字符数组 *  * @param data *            字节数组 * @return base64字符数组 */private static char[] encode(byte[] data) {char[] out = new char[((data.length + 2) / 3) * 4];for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {boolean quad = false;boolean trip = false;int val = (0xFF & (int) data[i]);val <<= 8;if ((i + 1) < data.length) {val |= (0xFF & (int) data[i + 1]);trip = true;}val <<= 8;if ((i + 2) < data.length) {val |= (0xFF & (int) data[i + 2]);quad = true;}out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];val >>= 6;out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];val >>= 6;out[index + 1] = alphabet[val & 0x3F];val >>= 6;out[index + 0] = alphabet[val & 0x3F];}return out;}/** * 将一个base64字符数组解码成一个字节数组 *  * @param data *            base64字符数组 * @return 返回解码以后的字节数组 */private static byte[] decode(char[] data) {int len = ((data.length + 3) / 4) * 3;if (data.length > 0 && data[data.length - 1] == '=')--len;if (data.length > 1 && data[data.length - 2] == '=')--len;byte[] out = new byte[len];int shift = 0;int accum = 0;int index = 0;for (int ix = 0; ix < data.length; ix++) {int value = codes[data[ix] & 0xFF];if (value >= 0) {accum <<= 6;shift += 6;accum |= value;if (shift >= 8) {shift -= 8;out[index++] = (byte) ((accum >> shift) & 0xff);}}}if (index != out.length)throw new Error("miscalculated data length!");return out;}/** * base64字符集 0..63 */static private char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();/** * 初始化base64字符集表 */static private byte[] codes = new byte[256];static {for (int i = 0; i < 256; i++)codes[i] = -1;for (int i = 'A'; i <= 'Z'; i++)codes[i] = (byte) (i - 'A');for (int i = 'a'; i <= 'z'; i++)codes[i] = (byte) (26 + i - 'a');for (int i = '0'; i <= '9'; i++)codes[i] = (byte) (52 + i - '0');codes['+'] = 62;codes['/'] = 63;} /**     * 将字符串通过base64转码     * @param str 要转码的字符串     * @return 返回转码后的字符串     */    public static String strToBase64Str(String str)    {        return new String(encode(str.getBytes()));    }        /**     * 将base64码反转成字符串     * @param base64Str base64码     * @return 返回转码后的字符串     */    public static String base64StrToStr(String base64Str)    {        char[] dataArr = new char[base64Str.length()];        base64Str.getChars(0, base64Str.length(), dataArr, 0);        return new String(decode(dataArr));    }        /**     * 将字节数组通过base64转码     * @param byteArray 字节数组     * @return 返回转码后的字符串     */    public static String byteArrayToBase64Str(byte byteArray[])    {        return new String(encode(byteArray));    }        /**     * 将base64码转换成字节数组     * @param base64Str base64码     * @return 返回转换后的字节数组     */    public static byte[] base64StrToByteArray(String base64Str)    {        char[] dataArr = new char[base64Str.length()];        base64Str.getChars(0, base64Str.length(), dataArr, 0);        return decode(dataArr);    }    /** * @param args * @throws UnsupportedEncodingException  */public static void main(String[] args) throws Exception {String strSrc = "Man";String strOut = Base64Utils.strToBase64Str(strSrc);System.out.println("源字符串 "+strSrc+" 的Base64码是:"+strOut);String strOut2 = Base64Utils.base64StrToStr(strOut);        System.out.println("Base64码 "+strOut+" 的对应源字符串为:"+strOut2);                  byte[] inByteArray={'a','b','c'};        String base64Str=Base64Utils.byteArrayToBase64Str(inByteArray);        StringBuilder sb=new StringBuilder();        sb.append('[');        for (int i = 0; i < inByteArray.length; i++) {sb.append(inByteArray[i]+" ");}        sb.append(']');        System.out.println("字节数组:"+sb+" 的Base64码是:"+base64Str);                byte[] outByteArray=Base64Utils.base64StrToByteArray(base64Str);        StringBuilder sb2=new StringBuilder();        sb2.append('[');        for (int i = 0; i < outByteArray.length; i++) {sb2.append(outByteArray[i]+" ");}        sb2.append(']');        System.out.println("Base64码为"+base64Str+" 的对应字节数组为:"+sb2);       }}

运行效果如下:

源字符串 Man 的Base64码是:TWFuBase64码 TWFu 的对应源字符串为:Man字节数组:[97 98 99 ] 的Base64码是:YWJjBase64码为YWJj 的对应字节数组为:[97 98 99 ]


 



                            ====================================================================================

  作者:欧阳鹏  欢迎转载,与人分享是进步的源泉!

  转载请保留原文地址:http://blog.csdn.net/ouyang_peng

====================================================================================

 


1 0
原创粉丝点击