【算法记录】Java - Base64编码解码源码
Base64编码表
索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 | 索引 | 对应字符 |
---|---|---|---|---|---|---|---|
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 | ||
15 | P | 32 | g | 49 | x | ||
16 | Q | 33 | h | 50 | y |
Base64基本原理
- 一、要编码的数据3个byte为一组,共3*8=24个bit
- 二、24个bit每6个一组,共分为四组
- 三、6位所表示数字的最大值为(2 ^ 6) - 1 = 63,刚好对应上面的编码表,即3个byte的原始数据编码后得到4个byte的数据
- 四、如果要编码的数据长度不是3的倍数,即最后一组数据凑不出24个bit,那么在最后面补位0
tips:
// 要编码的数据
String src = "mengxin";
// 对应的字节数组
byte[] src = new byte[]{109, 101, 110, 103, 120, 105, 110}
// 要编码的数据长度为7,前面的[109, 101, 110, 103, 120, 105]正常编码,后面剩下一个110对应的二进制为01101110
// 补0后得到011011100000000000000000
// 每6位为一组,共四组
// (1) 011011:对应的数字为27,这一组含有原本的位,所以正常查找编码表
// (2) 100000:对应的数字为32,这一组含有原本的位,所以正常查找编码表
// (3) 000000:对应的数字为0,这一组完全是由补位得到的,所以填充“=”
// (4) 000000:对应的数字为0,这一组完全是由补位得到的,所以填充“=”
// 解码原理相同,逆推即可
这里有一个动画讲解教程:
【【动画密码学】Base64编码&解码算法】https://www.bilibili.com/video/BV1Hp4y1g7Ex/?share_source=copy_web&vd_source=2c801bab51441760fc5e8a76d502c656
这里是我练习的编码解码源代码,比较简陋,仅作为理解使用,开发环境还是使用别人开发好的
- 没有进行细节处理,不喜勿喷,我的算法能力确实比较差
import java.io.ByteArrayOutputStream;
public class Base64 {
private static final String Base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
public static void main(String[] args) throws Exception {
System.out.println(Encode("mengxin".getBytes()));
System.out.println(new String(Decode("bWVuZ3hpbg==")));
}
/**
* Base64编码
* @param src 要编码的数据
* @return Base64编码后的字符串
*/
public static String Encode(byte[] src) {
int paddings = src.length % 3;
StringBuffer sb = new StringBuffer();
int i = 0;
for (; i < src.length - paddings; i += 3) {
sb.append(Base64EncodeChars.charAt(src[i] >> 2));
sb.append(Base64EncodeChars.charAt(((src[i] & 3) << 4) | (src[i + 1] >> 4)));
sb.append(Base64EncodeChars.charAt(((src[i + 1] & 15) << 2) | (src[i + 2] >> 6)));
sb.append(Base64EncodeChars.charAt(src[i + 2] & 63));
}
if (paddings == 2) {
sb.append(Base64EncodeChars.charAt(src[i] >> 2));
sb.append(Base64EncodeChars.charAt(((src[i] & 3) << 4) | (src[i + 1] >> 4)));
sb.append(Base64EncodeChars.charAt((src[i + 1] & 15) << 2));
sb.append("=");
} else if (paddings == 1) {
sb.append(Base64EncodeChars.charAt(src[i] >> 2));
sb.append(Base64EncodeChars.charAt((src[i] & 3) << 4));
sb.append("=");
sb.append("=");
}
return sb.toString();
}
/**
* Base64解码
* @param src 要解码的字符串
* @return Base64解码后的数据
*/
public static byte[] Decode(String src) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = 0;
for (; i < src.length() - 4; i += 4) {
int i1 = Base64EncodeChars.indexOf(src.charAt(i));
int i2 = Base64EncodeChars.indexOf(src.charAt(i + 1));
int i3 = Base64EncodeChars.indexOf(src.charAt(i + 2));
int i4 = Base64EncodeChars.indexOf(src.charAt(i + 3));
baos.write((i1 << 2) | (i2 >> 4));
baos.write(((i2 & 15) << 4) | (i3 >> 2));
baos.write(((i3 & 3) << 6) | i4);
//System.out.println(i1 + "|" + i2 + "|" + i3 + "|" + i4);
}
int i1 = Base64EncodeChars.indexOf(src.charAt(i)) << 2 | (Base64EncodeChars.indexOf(src.charAt(i + 1)) >> 4);
if ('=' == src.charAt(i + 2)){
baos.write(i1);
} else {
int i2 = (Base64EncodeChars.indexOf(src.charAt(i + 1)) << 4) | (Base64EncodeChars.indexOf(src.charAt(i + 2)) >> 2);
if ('=' == src.charAt(i + 3)) {
baos.write(i1);
baos.write(i2);
} else {
baos.write(i1);
baos.write(i2);
baos.write((Base64EncodeChars.indexOf(src.charAt(i + 2)) << 6) | (Base64EncodeChars.indexOf(src.charAt(i + 3))));
}
}
return baos.toByteArray();
}
}