手写Java版Base64算法

Base64概述

Base64就是选出64个字符:a-z、A-Z、0-9、+、/(再加上作为垫字的"=",实际上是65个字符),作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

转换方式可以分为四步:

  • 第一步,将每三个字节作为一组,一共是24个二进制位。
  • 第二步,将这24个二进制位分为四组,每个组有6个二进制位。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。
  • 第四步,根据下表,得到扩展后的每个字节的对应符号,这就是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将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。

示例

单词Man转成Base64编码:
在这里插入图片描述

  • 第一步,“M”、“a”、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。
  • 第二步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。
  • 第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。
  • 第四步,根据上表,得到每个值对应Base64编码,即T、W、F、u。

字节数不足三

二个字节

二个字节的情况:将这二个字节的一共16个二进制位,按照上面的规则,转成三组,最后一组除了前面加两个0以外,后面也要加两个0。这样得到一个三位的Base64编码,再在末尾补上一个"="号。

一个字节

一个字节的情况:将这一个字节的8个二进制位,按照上面的规则转成二组,最后一组除了前面加二个0以外,后面再加4个0。这样得到一个二位的Base64编码,再在末尾补上两个"="号。

Java实现

public class MyBase64 {

  private static final char[] CHS = {
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
      'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
      'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
      'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};

  private static final Map<Byte, Byte> CHS_MAP = new HashMap<>(64);

  static {
    for (int i = 0; i < CHS.length; i++) {
      CHS_MAP.put((byte) CHS[i], (byte) i);
    }
  }

  public static byte[] encode(byte[] bytes) {

    int groupCount = bytes.length / 3;
    int remainCount = bytes.length % 3;

    int encLength;
    if (remainCount == 0) {
      encLength = groupCount * 4;
    } else {
      encLength = (groupCount + 1) * 4;
    }

    int index, encI;
    byte b1, b2, b3;

    byte[] encBuf = new byte[encLength];

    for (int i = 0; i < groupCount; i++) {
      index = i * 3;

      b1 = bytes[index];
      b2 = bytes[index + 1];
      b3 = bytes[index + 2];

      encI = i * 4;
      encBuf[encI] = (byte) CHS[(b1 >> 2) & 0x3F];
      encBuf[encI + 1] = (byte) CHS[((b1 << 4) & 0x30) | ((b2 >> 4) & 0x0F)];
      encBuf[encI + 2] = (byte) CHS[((b2 << 2) & 0x3C) | ((b3 >> 6) & 0x03)];
      encBuf[encI + 3] = (byte) CHS[b3 & 0x3F];
    }

    if (remainCount == 2) {
      index = groupCount * 3;
      b1 = bytes[index];
      b2 = bytes[index + 1];
      b3 = 0;

      encI = groupCount * 4;
      encBuf[encI] = (byte) CHS[(b1 >> 2) & 0x3F];
      encBuf[encI + 1] = (byte) CHS[((b1 << 4) & 0x30) | ((b2 >> 4) & 0x0F)];
      encBuf[encI + 2] = (byte) CHS[((b2 << 2) & 0x3C) | ((b3 >> 6) & 0x03)];
      encBuf[encI + 3] = '=';
    }

    if (remainCount == 1) {
      index = groupCount * 3;
      b1 = bytes[index];
      b2 = 0;

      encI = groupCount * 4;
      encBuf[encI] = (byte) CHS[(b1 >> 2) & 0x3F];
      encBuf[encI + 1] = (byte) CHS[((b1 << 4) & 0x30) | ((b2 >> 4) & 0x0F)];
      encBuf[encI + 2] = encBuf[encI + 3] = '=';
    }

    return encBuf;
  }

  public static byte[] decode(byte[] encBytes) {

    int encLen = encBytes.length;
    int groupCount = encLen / 4;

    int decLen;
    int remainCount;
    if (encBytes[encLen - 1] == '=') {
      if (encBytes[encLen - 2] == '=') {
        decLen = groupCount * 3 - 2;
        remainCount = 1;
      } else {
        decLen = groupCount * 3 - 1;
        remainCount = 2;
      }
    } else {
      decLen = groupCount * 3;
      remainCount = 0;
    }

    int index, index2;
    byte[] decBytes = new byte[decLen];
    byte b1, b2, b3;

    for (int i = 0; i < groupCount - 1; i++) {
      decodeGroup(encBytes, decBytes, i);
    }

    if (remainCount == 2) {
      index = (groupCount - 1) * 4;
      b1 = CHS_MAP.get(encBytes[index]);
      b2 = CHS_MAP.get(encBytes[index + 1]);
      b3 = CHS_MAP.get(encBytes[index + 2]);

      index2 = (groupCount - 1) * 3;
      decBytes[index2] = (byte) (((b1 << 2) & 0xFF) | ((b2 >> 4) & 0xFF));
      decBytes[index2 + 1] = (byte) (((b2 << 4) & 0xFF) | ((b3 >> 2) & 0xFF));
    }

    if (remainCount == 1) {
      index = (groupCount - 1) * 4;
      b1 = CHS_MAP.get(encBytes[index]);
      b2 = CHS_MAP.get(encBytes[index + 1]);
      index2 = (groupCount - 1) * 3;
      decBytes[index2] = (byte) (((b1 << 2) & 0xFF) | ((b2 >> 4) & 0xFF));
    }

    if (remainCount == 0) {
      decodeGroup(encBytes, decBytes, groupCount - 1);
    }

    return decBytes;
  }

  private static void decodeGroup(byte[] encBytes, byte[] decBytes, int i) {
    byte b1, b2, b3, b4;

    int index = i * 4;

    b1 = CHS_MAP.get(encBytes[index]);
    b2 = CHS_MAP.get(encBytes[index + 1]);
    b3 = CHS_MAP.get(encBytes[index + 2]);
    b4 = CHS_MAP.get(encBytes[index + 3]);

    int index2 = i * 3;
    decBytes[index2] = (byte) (((b1 << 2) & 0xFF) | ((b2 >> 4) & 0xFF));
    decBytes[index2 + 1] = (byte) (((b2 << 4) & 0xFF) | ((b3 >> 2) & 0xFF));
    decBytes[index2 + 2] = (byte) (((b3 << 6) & 0xFF) | (b4 & 0xFF));
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值