Base64是网络上最常见的用于加密传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
这样说会不会太抽象了?不怕,我们来看一个例子:
转换前 | aaaaaabb | ccccdddd | eeffffff | | 转换后 | 00aaaaaa | 00bbcccc | 00ddddee | 00ffffff |
应该很清楚了吧?上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
|
|
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(摘自RFC2045)
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
让我们再来看一个实际的例子,加深印象!
转换前 |
10101101 |
10111010 |
01110110 |
|
转换后 |
00101011 |
00011011 |
00101001 |
00110110 |
十进制 |
43 |
27 |
41 |
54 |
对应码表中的值 |
r |
b |
p |
2 |
所以上面的24位编码,编码后的Base64值为 rbp2
解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。
(解码只是编码的逆过程,在此我就不多说了,另外有关MIME的RFC还是有很多的,如果需要详细情况请自行查找。)
下面的Base64编码/解码程序来自网上。
一、用SUN的API解码和编码
import java.io.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class Base64
{
public static void main(String[] args) {
if (args.length == 2) {
String string = Base64.encode(args[0]);
Base64.decode(string, args[1]);
} else
System.out.println("usage: java Base64 inputFile outputFile");
}
public static String encode(String fileName) {
String string = null;
try {
InputStream in = new FileInputStream(fileName);
// in.available()返回文件的字节长度
byte[] bytes = new byte[in.available()];
// 将文件中的内容读入到数组中
in.read(bytes);
string = new BASE64Encoder().encode(bytes);
in.close();
} catch (FileNotFoundException fe) {
fe.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
}
return string;
}
public static void decode(String string, String fileName) {
try {
// 解码,然后将字节转换为文件
byte[] bytes = new BASE64Decoder().decodeBuffer(string);
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
byte[] buffer = new byte[1024];
FileOutputStream out = new FileOutputStream(fileName);
int bytesum = 0;
int byteread = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
}
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
二、
/* @author CuCuChen
* @version $Id$
*/
import java.io.*;
class Base64Helper {
//从文本文件对象中读取内容并转换为字符数组
public static char[] readChars(File file)
{
CharArrayWriter caw = new CharArrayWriter();
try
{
Reader fr = new FileReader(file);
Reader in = new BufferedReader(fr);
int count = 0;
char[] buf = new char[16384];
while ((count=in.read(buf)) != -1) {
if (count > 0) caw.write(buf, 0, count);
}
in.close();
}
catch (Exception e) { e.printStackTrace(); }
return caw.toCharArray();
}
//从字符串对象中读取内容并转换为字符数组
public static char[] readChars(String string)
{
CharArrayWriter caw = new CharArrayWriter();
try
{
Reader sr = new StringReader(string.trim());
Reader in = new BufferedReader(sr);
int count = 0;
char[] buf = new char[16384];
while ((count=in.read(buf)) != -1) {
if (count > 0) caw.write(buf, 0, count);
}
in.close();
}
catch (Exception e) { e.printStackTrace(); }
return caw.toCharArray();
}
//从二进制文件对象中读取内容并转换为字节数组
public static byte[] readBytes(File file)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
InputStream fis = new FileInputStream(file);
InputStream is = new BufferedInputStream(fis);
int count = 0;
byte[] buf = new byte[16384];
while ((count=is.read(buf)) != -1) {
if (count > 0) baos.write(buf, 0, count);
}
is.close();
}
catch (Exception e) { e.printStackTrace(); }
return baos.toByteArray();
}
//写字节数组内容到二进制文件
public static void writeBytes(File file, byte[] data) {
try {
OutputStream fos = new FileOutputStream(file);
OutputStream os = new BufferedOutputStream(fos);
os.write(data);
os.close();
}
catch (Exception e) { e.printStackTrace(); }
}
//写字符数组内容到文本文件
public static void writeChars(File file, char[] data) {
try {
Writer fos = new FileWriter(file);
Writer os = new BufferedWriter(fos);
os.write(data);
os.close();
}
catch (Exception e) { e.printStackTrace(); }
}
}
public class Base64{
//编码文件对象所指的文件
static public char[] encode(File file){
if (!file.exists()) {
System.err.println("错误:文件不存在!");
return null;
}
return encode(Base64Helper.readBytes(file));
}
//编码文件名所指的文件
static public char[] encode(String filename){
File file = new File(filename);
if (!file.exists()) {
System.err.println("错误:文件“"+filename+"”不存在!");
return null;
}
return encode(Base64Helper.readBytes(file));
}
//编码传入的字节数组,输出编码后的字符数组
static public char[] encode(byte[] data)
{
char[] out = new char[((data.length + 2) / 3) * 4];
//
// 对字节进行Base64编码,每三个字节转化为4个字符.
// 输出总是能被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;
}
static public byte[] decode(char[] data)
{
// 程序中有判断如果有回车、空格等非法字符,则要去掉这些字符
// 这样就不会计算错误输出的内容
int tempLen = data.length;
for( int ix=0; ix< data.length; ix++ )
{
if( (data[ix] > 255) || codes[ data[ix] ] < 0 )
--tempLen; // 去除无效的字符
}
// 计算byte的长度
// -- 每四个有效字符输出三个字节的内容
// -- 如果有额外的3个字符,则还要加上2个字节,
// 或者如果有额外的2个字符,则要加上1个字节
int len = (tempLen / 4) * 3;
if ((tempLen % 4) == 3) len += 2;
if ((tempLen % 4) == 2) len += 1;
byte[] out = new byte[len];
int shift = 0;
int accum = 0;
int index = 0;
// 一个一个字符地解码(注意用的不是tempLen的值进行循环)
for (int ix=0; ix< data.length; ix++)
{
int value = (data[ix]>255)? -1: codes[ data[ix] ];
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("数据长度不一致(实际写入了 " + index + "字节,但是系统指示有" + out.length + "字节)");
}
return out;
}
//
// 用于编码的字符
//
static private char[] alphabet ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".toCharArray();
//
// 用于解码的字节(0-255)
//
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;
}
public static void main (String [] args){
String key = new String("Spider");
byte[] a = key.getBytes();
char[] b = Base64.encode(a) ;
System.out.println(new String(b));
//for(int i=0;i< b.length;i++){
// System.out.println(b[i]);
//}
byte[] c = Base64. decode(b);
System.out.println(new String(c));
}
}
运行结果:
C:\java>java Base64
U3BpZGVy
Spider