zoukankan      html  css  js  c++  java
  • 我的Java开发学习之旅------>Base64的编码思想以及Java实现

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

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


    一、编码规则

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

    详细来说,转换方式能够分为四步。

    • 第一步,将每三个字节作为一组,一共是24个二进制位。

    • 第二步,将这24个二进制位分为四组,每一个组有6个二进制位。

    • 第三步,在每组前面加两个00。扩展成32个二进制位,即四个字节。
    • 第四步,依据下表。得到扩展后的每一个字节的相应符号。这就是Base64的编码值。

    注:BASE64字符表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/



    Base64 编码表
    Value Char
    Value Char
    Value Char
    Value Char
    0 A 16 Q 32 g 48 w
    1 B 17 R 33 h 49 x
    2 C 18 S 34 i 50 y
    3 D 19 T 35 j 51 z
    4 E 20 U 36 k 52 0
    5 F 21 V 37 l 53 1
    6 G 22 W 38 m 54 2
    7 H 23 X 39 n 55 3
    8 I 24 Y 40 o 56 4
    9 J 25 Z 41 p 57 5
    10 K 26 a 42 q 58 6
    11 L 27 b 43 r 59 7
    12 M 28 c 44 s 60 8
    13 N 29 d 45 t 61 9
    14 O 30 e 46 u 62 +
    15 P 31 f 47 v 63 /



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


    举一个详细的实例。演示英语单词Man怎样转成Base64编码。

    文本 M a n
    ASCII编码 77 97 110
    二进制位 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
    索引 19 22 5 46
    Base64编码 T W F u

    • 第一步。"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

    二进制位 0 1 0 0 0 0 0 1















    二进制位(补0) 0 1 0 0 0 0 0 1 0 0 0 0











    Base64编码 Q Q = =
    文本(2 Byte) B C
    二进制位 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1

    x x x x x x
    二进制位(补0) 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 x x x x x x
    Base64编码 Q k M  =

    因此。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码是:TWFu
    Base64码 TWFu 的相应源字符串为:Man
    字节数组:[97 98 99 ] 的Base64码是:YWJj
    Base64码为YWJj 的相应字节数组为:[97 98 99 ]




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

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

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

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

     


  • 相关阅读:
    [NOIP2010]引水入城
    [NOIP2009]靶形数独
    设计模式学习笔记——桥接模式(Bridge)
    BootStrap3.0学习--JavaScript 插件
    BootStrap3.0学习--组件
    BootStrap3.0学习--全局 CSS 样式
    BootStrap3.0学习--起步
    设计模式之第11章-建造者模式(Java实现)
    设计模式之第10章-桥接模式(Java实现)
    设计模式之第9章-原型模式(Java实现)
  • 原文地址:https://www.cnblogs.com/zsychanpin/p/7072603.html
Copyright © 2011-2022 走看看