base64概念
base64编码简单的说就是对字节流的一种编码。
base64的码表使用[A~Z] 、 [a~z] 、 [0-9] 、 + 、 / 一共64个字符组成,分别对应[0-63]的索引。
编码方法:将一个字符串按照某种字符集获得字节流后,将字节流每6位依次取出,6位bit最大值为63,正好对应base64的码表,不足6位时后面补0,根据6位bit对应的十进制数为索引找到base64码表中的编码。可以看出原始字节流3个字节,3*8bit = 24bit 等于 base64编码的4个编码 4*6bit=24bit 长度,当最后bit数不够产生4个base64编码时会用"="补在base64编码的后面。
用一个简单例子梳理一下流程,例如获得字符A的base64编码,A使用gbk字符集:
1. 获取A的字节流(byte数组)
A 对应ascii码65,对应二进制01000001
2. 按照base64格式每6个bit进行编码
01000001 对应 010000 010000
3. 将6个bit转成base64编码
010000对应十进制 16 ,对应base64编码 Q
4. 不足4个编码以'='补充
最后结果 QQ==
MIME中的base64:
在邮件收发时邮件的主题、邮箱地址、附件名称等经常会用到base64和Quoted-printable等进行编码,在传输使用编码过的数据时会以=?[字符集]?[B/Q]?[具体base64编码]?= 来进行传输。
例如,如下邮件头信息中的 From、Subject信息是使用了base64编码
Received: from qiye.163.com (unknown [192.168.224.143])
by mfast2 (Coremail) with SMTP id yOCowEBpbkJXrQ5ZnB8KAA--.714S2;
Sun, 07 May 2017 13:15:03 +0800 (CST)
From: =?utf-8?B?5LyB5Lia6YKu566x?= <notice@qiye.163.com>
Reply-To: notice@qiye.163.com
To: xxxxx@xxx.xxx.com
Message-ID: <98944601.5.1494134105220.OfficialService-3.0.notice@qiye.163.com>
Subject: =?utf-8?B?W+S8geS4mumZkOaXtuemj+WIqV3msp/pgJrmiJDmnKzkuIA=?=
=?utf-8?B?6ZmN5YaN6ZmNLOeUteivneS8muiuruWFheWAvOWKoOmAgSE=?=
MIME-Version: 1.0
Content-Type: text/html; charset=utf-8
Content-Transfer-Encoding: 7bit
......
处理base64的工具
apache commons-codec 中提供的Base64工具 、 javax.mail 自带的编码解码工具MimeUtility。
下面是使用commons-codec和javax.mail的工具来编解码base64,和自己练习写的一个编解码base64工具的测试代码。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.mail.internet.MimeUtility;
import org.apache.commons.codec.binary.Base64;
public class CodeUtil {
//base64 code
public static Map<Integer, Character> base64Map= new HashMap<Integer, Character>();
static {
int ascii_num_A = 65;
for(int i=0 ;i<26 ; i++){
base64Map.put(i , (char)ascii_num_A++);
}
int ascii_num_a = 97;
for(int i=26 ;i<52 ; i++){
base64Map.put(i , (char)ascii_num_a++ );
}
int ascii_num_0 = 48;
for(int i=52 ;i<62 ; i++){
base64Map.put(i , (char)ascii_num_0++ );
}
base64Map.put(62, '+');
base64Map.put(63, '/');
}
/**
* 获取字符串对应的ascii码数组
* @param s
* @return int[]
* @throws Exception
*/
public static int[] getStringAscii(String s , String code) throws Exception{
StringBuilder sb = new StringBuilder();
byte[] bytes = s.getBytes(code);
int[] asc2 = new int[bytes.length];
for (int i = 0; i < bytes.length; i++) {
sb.append(bytes[i] + " ");
asc2[i] = bytes[i];
}
System.out.println(sb.toString());
return asc2;
}
/**
* 将asc2码转为二进制数组
* @param asc2
* @return
* @throws Exception
*/
public static String[] asciiToBinary(int[] asc2) throws Exception{
String[] binary = new String[asc2.length];
for(int i=0; i<asc2.length; i++){
String b = Integer.toBinaryString(asc2[i] & 0xff);
if(b.length() < 8){
for(int j=0 , k=8-b.length(); j<k ; j++){
b = '0' + b;
}
}
binary[i] = b;
System.out.print(b + " ");
}
System.out.println();
return binary;
}
/**
* 将二进制编码转为base64的格式
* 6位一组
* @param oriBinary
* @return
* @throws Exception
*/
public static String[] getBase64Binary(String[] oriBinary) throws Exception{
List<String> base64Binary = new ArrayList<String>();
for(int i=0 , j = oriBinary.length; i<j ; i++){
String oldBinary = oriBinary[i];
if(base64Binary.size() == 0){
base64Binary.add(oldBinary.substring(0, 6));
base64Binary.add(oldBinary.substring(6));
}else{
String curBinary = base64Binary.get(base64Binary.size()-1);
if(curBinary.length() < 6){
int l = 6 - curBinary.length();
curBinary += oldBinary.substring(0, l);
base64Binary.set(base64Binary.size()-1 , curBinary);
base64Binary.add(oldBinary.substring(l));
}else{
base64Binary.add(oldBinary.substring(0, 6));
base64Binary.add(oldBinary.substring(6));
}
}
}
if(base64Binary.size() > 0){
String curBinary = base64Binary.get(base64Binary.size()-1);
int l = 6 - curBinary.length();
if(l > 0){
for(int i=0; i<l ; i++){
curBinary += "0";
}
base64Binary.set(base64Binary.size()-1, curBinary);
}
}
String[] a = new String[base64Binary.size()];
return base64Binary.toArray(a);
}
/**
* 将字符串数组格式化为一个字符串,每个字符串间有一个空格
* @param ss
* @return
* @throws Exception
*/
public static String formateStringArray(String[] ss) throws Exception{
StringBuilder sb = new StringBuilder();
for(String s : ss){
sb.append(s + " ");
}
return sb.toString();
}
/**
* 将输入的字符串按指定编码转为base64
* @param str
* @param charset
* @return
* @throws Exception
*/
public static String encodeStrToBase64 (String str , String charset) throws Exception{
StringBuffer sb = new StringBuffer();
int[] asciis = getStringAscii(str, charset);
String[] binarys = asciiToBinary(asciis);
String[] base64Binary = getBase64Binary(binarys);
String formateBase64Binary = formateStringArray(base64Binary);
System.out.println(formateBase64Binary);
for(int i=0; i<base64Binary.length ; i++){
sb.append(base64Map.get(Integer.parseInt(base64Binary[i],2)));
}
int n = base64Binary.length % 4;
for(int i=0; i<n; i++){
sb.append("=");
}
return sb.toString();
}
public static void commonsCodec (String str, String charset) throws Exception {
System.out.println("\n\n********* 使用 org.apache.commons.codec.binary.Base64 工具进行 base64编码...");
String base64 = Base64.encodeBase64String(str.getBytes(charset));
System.out.println("原始字符串:" + str + " \n编码后:" + base64);
System.out.println("\n\n**************** 使用 org.apache.commons.codec.binary.Base64 工具进行 base64解码...");
byte[] bytes = Base64.decodeBase64(base64);
String newStr = new String(bytes, charset);
System.out.println("原始base64编码:" + base64 + "\n解码后:" + newStr);
}
public static void javamail(String str, String charset) throws Exception{
System.out.println("\n\n ********** 使用 javax.mail.internet.MimeUtility 工具 进行base64编码...");
String mimeBase64 = MimeUtility.encodeText(str ,charset , "B");
System.out.println("原始字符串:" + str + " \n编码后:" + mimeBase64);
System.out.println("\n\n *************** 使用javamail 的 javax.mail.internet.MimeUtility 工具 进行base64解码...");
System.out.println("原始base64编码:" + mimeBase64 + "\n解码后:" + MimeUtility.decodeText(mimeBase64));
}
public static void main(String[] args) throws Exception{
String str = "张三";
String charset = "gbk";
System.out.println(encodeStrToBase64(str, charset));
commonsCodec(str, charset);
javamail(str, charset);
}
}
结果:
-43 -59 -56 -3
11010101 11000101 11001000 11111101
110101 011100 010111 001000 111111 010000
1cXI/Q==
********* 使用 org.apache.commons.codec.binary.Base64 工具进行 base64编码...
原始字符串:张三
编码后:1cXI/Q==
**************** 使用 org.apache.commons.codec.binary.Base64 工具进行 base64解码...
原始base64编码:1cXI/Q==
解码后:张三
********** 使用 javax.mail.internet.MimeUtility 工具 进行base64编码...
原始字符串:张三
编码后:=?gbk?B?1cXI/Q==?=
*************** 使用javamail 的 javax.mail.internet.MimeUtility 工具 进行base64解码...
原始base64编码:=?gbk?B?1cXI/Q==?=
解码后:张三