Base64编码

package base64;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
/**
 * Base64是MIME邮件中常用的编码之一。
 * 编码方法:从输入数据流中每次取6bit, 将此6bit的值(0~63)作为索引去查表,输出相应字符。
 * 每3个字节将编码为4个字符(3x8=4x6);不满4个字符的以‘=’填充
 */
@SuppressWarnings("unused")
public class Base64 {
	
	public static final boolean ENCODE = true;//加密
    public static final boolean DECODE = false;//触密
    private static final int MAX_LINE_LENGTH = 76;//每行最大字符数
    private static final byte EQUALS_SIGN = 61;//==
    private static final byte NEW_LINE = 10;
	private static final byte BAD_ENCODING = -9;//退格
    private static final byte WHITE_SPACE_ENC = -5;//空格
    private static final byte EQUALS_SIGN_ENC = -1;//==
    private static final byte ALPHABET[] = {
        65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 
        75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 
        85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 
        101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 
        111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 
        121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 
        56, 57, 43, 47
    };
    private static final byte DECODABET[] = {
        -9, -9, -9, -9, -9, -9, -9, -9, -9, -5, 
        -5, -9, -9, -5, -9, -9, -9, -9, -9, -9, 
        -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, 
        -9, -9, -5, -9, -9, -9, -9, -9, -9, -9, 
        -9, -9, -9, 62, -9, -9, -9, 63, 52, 53, 
        54, 55, 56, 57, 58, 59, 60, 61, -9, -9, 
        -9, -1, -9, -9, -9, 0, 1, 2, 3, 4, 
        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 
        15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 
        25, -9, -9, -9, -9, -9, -9, 26, 27, 28, 
        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 
        39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 
        49, 50, 51, -9, -9, -9, -9
    };
	
    /**
	 * 读取Base64编码的数
	 */
	public static class InStream extends FilterInputStream {
		private boolean encode;//是否编码
		private int position;//buffer中的位置
		private byte[] buffer;//保存转换后的数据
		private int bufferLength;//buffer的长度(3或4)
		private int numSigBytes;//buffer中有效字节的长度
		private int lineLength;//一行的字符数
		private boolean breakLines;//是否换行

		/**
		 * 构造一个解码模式的类对象
		 */
		public InStream(InputStream in) {
			this(in, Base64.ENCODE);
		}
		/**
		 * 根据encode参数判断该对象采用的模式
		 */
		public InStream(InputStream in, boolean encode) {
			this(in, encode, true);
		}
		/**
		 * breakLines参数限定每行字符数
		 */
		public InStream(InputStream in, boolean encode, boolean breakLines) {
			super(in);
			this.breakLines = breakLines;
			this.encode = encode;
			this.bufferLength = encode ? 4 : 3;
			this.buffer = new byte[bufferLength];
			this.position = -1;
			this.lineLength = 0;
		}
		/**
		 * 从输入流读取足够的数据进行Base64规范的编码或解码,并且返回下一个字节
		 */
		public int read() throws IOException {
			if(position < 0) {//如果数据不存在
				if(encode) {
					byte[] b3 = new byte[3];
					int numBinaryBytes = 0;
					for(int i=0; i<3; i++) {//编码,读取3个字节
						int b = in.read();
						if(b >= 0) {//判断是否到流的末尾
							b3[i] = (byte)b;
							numBinaryBytes++;
						}
					}
					if(numBinaryBytes > 0) {
						encode3to4(b3, 0, numBinaryBytes, buffer, 0);
						position = 0;
						numSigBytes = 4;
					} else {
						return -1;
					}
				} else {
					byte[] b4 = new byte[4];
					int i = 0;
					for(i=0; i<4; i++) {//解码,读取4个有效字节
						int b = 0;
						do{ b=in.read();}
						while(b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC);
						if(b < 0) break;
						b4[i] = (byte)b;
					}
					if(i == 4) {
						numSigBytes = decode4to3(b4, 0, buffer, 0);
						position = 0;
					} else if(i == 0) {
						return -1;
					} else {
						throw new IOException("无效数据");
					}
				}
			} 
			if(position >= 0) {//数据已存在,读取数据
				if(position >= numSigBytes) return -1;
				if(encode && breakLines && lineLength >= MAX_LINE_LENGTH) {//判断数据是否超过限长
					lineLength = 0;
					return '\n';
				} else {
					lineLength ++;
					int b = buffer[position++];
					if(position >= bufferLength) position = -1;
					return b & 0xFF;//将字节转换为unsigned类型
				}
			} else {
				throw new IOException("无效数据");
			}
		}
		/**
		 * 读取数据,直至已经读取了len个字节或流的结束
		 */
		public int read(byte[] dest, int off, int len) throws IOException {
			int i,b;
			for(i=0; i<len; i++) {
				b = read();
				if(b >= 0)
					dest[off + i] = (byte)b;
				else if(i == 0) 
					return -1;
				else break;
			}
			return i;
		}
	}
	/**
	 * 按照Base64编码输出数据
	 */
	public static class OutStream extends FilterOutputStream {
		private boolean encode;
		private int position;
		private byte[] buffer;
		private int bufferLength;
		private int lineLength;
		private boolean breakLines;
		/**
		 * 构造一个编码的输出流类对象
		 */
		public OutStream(OutputStream out) {
			this(out, Base64.ENCODE);
		}
		/**
		 * 根据encode参数判断该类对象是编码模式还是解码模式
		 */
		public OutStream(OutputStream out, boolean encode) {
			this(out, encode, true);
		}
		/**
		 * breakLines参数限定每行字符数
		 */
		public OutStream(OutputStream out, boolean encode, boolean breakLines) {
			super(out);
			this.breakLines = breakLines;
			this.encode = encode;
			this.bufferLength = encode ? 3 : 4;
			this.buffer = new byte[bufferLength];
			this.position = 0;
			this.lineLength = 0;
		}
		/**
		 * 转化完成后,将字节定入输出流
		 * 如果是编码,则对字节进行缓存,每次缓存3个字节,然后执行写操作
		 * 如果是解码,则每次缓存4个字节
		 */
		public void write(int theByte) throws IOException {
			if(encode) {
				buffer[position++] = (byte)theByte;
				if(position >= bufferLength) {
					out.write(Base64.encode3to4(buffer, bufferLength));
					lineLength +=4;
					if(breakLines && lineLength >= MAX_LINE_LENGTH) {
						out.write(NEW_LINE);
						lineLength = 0;
					}
					position = 0;
				}
			} else {
				if(DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC) {
					buffer[position++] = (byte)theByte;
					if(position >= bufferLength) {
						out.write(Base64.decode4to3(buffer));
						position = 0;
					}
				} else if(DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC) {
					throw new IOException("无效数据");
				}
			}
		}
		/**
		 * 写入len个字节
		 */
		public void write(byte[] theBytes, int off, int len) throws IOException {
			for(int i=0; i<len; i++) {
				write(theBytes[off + i]);
			}
		}
		/**
		 * 编码时,对其进行补位;
		 * 解码时,如果Base64规范的输入没有正确补位将会抛异常
		 */
		public void flush() throws IOException {
			if(out != null) super.flush();
			if(position > 0) {
				if(encode) {
					out.write(Base64.encode3to4(buffer, position));
					position = 0;
				} else {
					throw new IOException("无效数据");
				}
			}
			if(out != null)
				out.flush();
		}
		/**
		 * 关闭并清空流
		 */
		public void close() throws IOException {
			if(out != null) {
				super.close();
				out.close();
				buffer = null;
				out = null;
			}
		}
	}
	/**
	 * 对threeBytes数组的前3个字节进行编码,并且返回一个Base64规范的4-byte数组
	 */
	private static byte[] encode3to4(byte[] threeBytes) {
		return encode3to4(threeBytes, 3);
	}
	/**
	 * threeBytes数组大小与numSigBytes相等
	 */
	private static byte[] encode3to4(byte[] threeBytes, int numSigBytes) {
		byte[] dest = new byte[4];
		encode3to4(threeBytes, 0, numSigBytes, dest, 0);
		return dest;
	}
	/**
	 * 对source数组按照Base64规范进行编码,并将结果写入destination数组
	 * srcOffset和destOffset确定数组起点
	 * source数组大小必须满足srcOffset+3, destination数组大小必须满足destOffset+4
	 * numSigBytes指定数组中的实际有效字节数
	 */
	private static byte[] encode3to4(byte[] source, int srcOffset, 
			int numSigBytes, byte[] destination, int destOffset) {
		/*
		 * 如果numSigBytes是1或2就创建一个用0初始化的buffer,并且向左移动24位;
		 * (其目的是为了将1完全清除,防止java在将一个字节转化成int型的时候,将值转化成负数)
		 * 
		 * 1、左移运算符<<使指定值的所有位都左移规定的次数,规则:
		 * 			丢弃最高位,0补最低位;
		 * 			如果移动的位数超过了该类型的最大位数,那么编译器会对移动的位数取模
		 * 2、右移运算符>>使指定值的所有位都右移规定的次数,规则:
		 * 			符号位不变,左边补上符号位;
		 * 3、无符号右移运算符>>>	:忽略了符号位扩展,0补最高位 ;只是对32位和64位的值有意义 	
		 * 右移相当于除,左移相当于乘,左移一位乘2,左移二位乘4。。。	
		 */
		int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) | 
				(numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) |
				(numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
		//根据有效的字节数进行转换
		switch(numSigBytes) {
		case 3:
			destination[destOffset] = ALPHABET[(inBuff >>> 18)];
			destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
			destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
			destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
			return destination;
		case 2:
			destination[destOffset] = ALPHABET[(inBuff >>> 18)];
			destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
			destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
			destination[destOffset + 3] = EQUALS_SIGN;
			return destination;
		case 1:
			destination[destOffset] = ALPHABET[(inBuff >>> 18)];
			destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
			destination[destOffset + 2] = EQUALS_SIGN;
			destination[destOffset + 3] = EQUALS_SIGN;
			return destination;
		default: return destination; 
		}
	}
	/**
	 * 对字节数组进行编码
	 */
	public static String encodeBytes(byte[] source) {
		return encodeBytes(source, true);
	}
	/**
	 * 对字节数组进行编码
	 */
	public static String encodeBytes(byte[] source, boolean breakLines) {
		return encodeBytes(source, 0, source.length, breakLines);
	}
	/**
	 * 对字节数组进行编码
	 */
	public static String encodeBytes(byte[] source, int off, int len) {
		return encodeBytes(source, off, len, true);
	}
	/**
	 * 实际进行编码的方法
	 */
	public static String encodeBytes(byte[] source, int off, int len, boolean breakLines) {
		int len43 = len * 4 / 3 , d = 0, e = 0 , len2 = len - 2, lineLength = 0;
		byte[] outBuff = new byte[len43 + ((len % 3) > 0 ? 4 : 0) + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)];
		for(;d < len2; d += 3, e += 4) {
			encode3to4(source, d+off, 3, outBuff, e);
			lineLength += 4;
			if(breakLines && lineLength == MAX_LINE_LENGTH) {
				outBuff[e + 4] = NEW_LINE;
				e++;
				lineLength = 0;
			}
		}
		if(d < len) {
			encode3to4(source, d+off, len-d, outBuff, e);
			e += 4;
		}
		return new String(outBuff, 0, e);
	}
	/**
	 * 对String进行编码
	 */
	public static String encodeString(String s) {
		return encodeString(s, true);
	}
	/**
	 * 对String进行编码
	 */
	public static String encodeString(String s, boolean breakLines) {
		return encodeBytes(s.getBytes(), breakLines);
	}
	/**
	 * 按照Base64编码串行化对象Object
	 */
	public static String encodeobject(Serializable sobj) {
		return encodeObject(sobj, true);
	}
	/**
	 * 实际串行化对象Object
	 */
	public static String encodeObject(Serializable sobj, boolean breakLines) {
		ByteArrayOutputStream baos = null;
		OutputStream b64os = null;
		ObjectOutputStream oos = null;
		try {
			baos = new ByteArrayOutputStream();
			b64os = new Base64.OutStream(baos, ENCODE, breakLines);
			oos = new ObjectOutputStream(b64os);
			oos.writeObject(sobj);
		} catch(IOException e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				oos.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			try {
				b64os.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			try {
				baos.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		return new String(baos.toByteArray());
	}
	/**
	 * 读取文件中的数据
	 */
	public static byte[] readFile(String file, boolean encode) {
		return readFile(new File(file), encode);
	}
	/**
	 * 根据encode参数,读取文件中的数据
	 */
	public static byte[] readFile(File file, boolean encode) {
		byte[] data = new byte[1024];//文件中的字符数不能超过1024
		byte[] returnValue = null;
		int nextIndex = 0;
		int b = -1;
		Base64.InStream bis = null;
		
		try {
			bis = new Base64.InStream(new BufferedInputStream(new FileInputStream(file)), encode);
			while((b = bis.read()) >= 0) {
				if(nextIndex > data.length) {//重新设定数组长度
					byte[] temp = new byte[data.length << 1];
					System.arraycopy(data, 0, temp, 0, data.length);//截取数组
					data = temp;
				}
				data[nextIndex++] = (byte)b;
			}
			returnValue = new byte[nextIndex];
			System.arraycopy(data, 0, returnValue, 0, nextIndex);
		} catch (IOException e) {
			returnValue = null;
		} finally {
			try {
				if(bis != null)
				bis.close();
			} catch (IOException e) {
			}
		}
		return returnValue;
	}
	/**
	 * 将字节数组写入文件
	 */
	public static boolean writeFile(byte[] data, String file, boolean encode) {
		return writeFile(data, 0, data.length, new File(file), encode);
	}
	/**
	 * 将字节数组写入文件
	 */
	public static boolean writeFile(byte[] data, File file, boolean encode) {
		return writeFile(data, 0, data.length, file, encode);
	}
	/**
	 * 根据encode参数,将字节数组写入文件
	 */
	public static boolean writeFile(byte[] data, int offset, int length, File file, boolean encode) {
		Base64.OutStream bos = null;
		boolean success = false;
		try {
			bos = new Base64.OutStream(new BufferedOutputStream(new FileOutputStream(file)), encode);
			bos.write(data, offset, length);
			success = true;
		} catch (IOException e) {
			success = false;
		} finally {
			try {
				bos.close();
			} catch (IOException e) {
			}
		}
		return success;
	}
	/**
	 * 对文件数据进行编码,返回编码后的字符串,抛异常则返回null
	 */
	public static String encodeFromFile(String rawfile) {
		byte[] ebytes = readFile(rawfile, ENCODE);
		return ebytes == null ? null : new String(ebytes);
	}
	/**
	 * 对文件数据进行解码,返回解码后的字符串,抛异常则返回null
	 */
	public static byte[] decodeFromFile(String encfile) {
		return readFile(encfile, DECODE);
	}
	/**
	 *  将编码后的数据写入文件
	 */
	public static boolean encodeToFile(byte[] rawdata, String file) {
		return writeFile(rawdata, file, ENCODE);
	}
	/**
	 *  将解码后的数据写入文件
	 */
	public static boolean decodeToFile(byte[] encdata, String file) {
		return writeFile(encdata, file, DECODE);
	}
	/**
	 *  对fourBytes数组进行解码,并返回解码后的数组
	 */
	private static byte[] decode4to3(byte[] fourBytes) {
		byte[] outBuff1 = new byte[3];
		int count = decode4to3(fourBytes, 0, outBuff1, 0);
		byte[] outBuff2 = new byte[count];
		for(int i=0; i<count; i++) outBuff2[i] = outBuff1[i];
		return outBuff2;
	}
	/**
	 *  对fourBytes数组进行解码,并返回解码后的数组
	 */
	private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset) {
		if(source[srcOffset + 2] == EQUALS_SIGN) {
			int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) |
						  ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
			destination[destOffset] = (byte)(outBuff >>> 16);
			return 1;
		} else if(source[srcOffset + 3] == EQUALS_SIGN) {
			int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) |
					  	  ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) |
					  	  ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
			destination[destOffset] = (byte)(outBuff >>> 16);
			destination[destOffset + 1] = (byte)(outBuff >>> 8);
			return 2;
		} else {
			int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) |
				  	  	  ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) |
				  	  	  ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) |
						  ((DECODABET[source[srcOffset + 3]] & 0xFF));
			destination[destOffset] = (byte)(outBuff >> 16);
			destination[destOffset + 1] = (byte)(outBuff >> 8);
			destination[destOffset + 2] = (byte)(outBuff);
			return 3;
		}
	}
	/**
	 *  对String进行解码,并返回解码后的数组
	 */
	public static byte[] decode(String s) {
		byte[] bytes = s.getBytes();
		return decode(bytes, 0, bytes.length);
	}
	/**
	 *  对String进行解码,并返回String
	 */
	public static String decodeToString(String s) {
		return new String(decode(s));
	}
	/**
	 *  对Base64规范的数据进行解码,并且反串行化得到一个java对象
	 */
	public static Object decodeToObject(String encodeedObject) {
		byte[] objBytes = decode(encodeedObject);
		ByteArrayInputStream bais = null;
		ObjectInputStream ois = null;
		try {
			bais = new ByteArrayInputStream(objBytes);
			ois = new ObjectInputStream(bais);
			return ois.readObject();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				bais.close();
			} catch (IOException e) {
			}
			try {
				ois.close();
			} catch (IOException e) {
			}
		}
	}
	/**
	 *  对Base64规范的数据进行解码
	 */
	public static byte[] decode(byte[] source, int off, int len) {
		int len34 = len * 3 / 4, outBuffPosn = 0, b4Posn = 0, i = 0;
		byte[] outBuff = new byte[len34];
		byte[] b4 = new byte[4];
		byte sbiCrop = 0;
		byte sbiDecode = 0;
		for(i=0; i<len; i++) {
			sbiCrop = (byte)(source[i] & 0x7f);//只需要低位的7个bit
			sbiDecode = DECODABET[sbiCrop];
			if(sbiDecode >= WHITE_SPACE_ENC) {//空格
				if(sbiDecode >= EQUALS_SIGN_ENC) {//==
					b4[b4Posn++] = sbiCrop;
					if(b4Posn > 3) {
						outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
						b4Posn = 0;
						//如果没有"=="就跳出循环
						if(sbiCrop == EQUALS_SIGN) break;
					}
				}
			} else {
				return null;
			}
		}
		byte[] out = new byte[outBuffPosn];
		System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
		return out;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值