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;
}
}
Base64编码
最新推荐文章于 2021-12-15 08:19:54 发布