TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
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
复制代码
源码下载:http://file.javaxxz.com/2014/11/8/000503375.zip |
|