Java实现Base64工具类(编码和解码)

一、Base64简介

  Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。大家可查看RFC2045~RFC2049,上面有MIME的详细规范。

Base64转换表

索引对应的字符索引对应的字符索引对应的字符
0A26a520
1B27b531
2C28c542
3D29d553
4E30e564
5F31f575
6G32g586
7H33h597
8I34i608
9J35j619
10K36k62+
11L37l63/
12M38m
13N39n
14O40o
15P41p
16Q42q
17R43r
18S44s
19T45t
20U46u
21V47v
22W48w
23X49x
24Y50y
25Z51z

二、Base64编译过程

  • 获取原始字符串对应的ASCII的值
  • 把ASCII的值转成二进制数据
  • 把所有的二进制数据进行合并
  • 将合并后的数据每6个一组进行分组,不足6位则补零
  • 把分组后的数据前面补两个零变成二进制
  • 把补零后的二进制数据转换为十进制
  • 参照base64转换表找到对应的数值
  • 对结果长度不是4的倍数则进行填充(一般是"="符号)

Base64编译过程图解如下:
在这里插入图片描述
编译结果校验:

/**
     * Java原生Base64编码校验(Alian编码后的值)
     * 此处单元测试的注解是采用:org.junit.Test
     */
    @Test
    public void verify() {
        System.out.println("------------------Java原生Base64编码校验--------------------------");
        //定义要编码的字符串
        String plainText = "Alian";
        System.out.println("原始字符串:" + plainText);
        //获取Java原生的Base64编码对象(java.util.Base64.getEncoder())
        String encode = Base64.getEncoder().encodeToString(plainText.getBytes(StandardCharsets.UTF_8));
        System.out.println("Java原生编码后的base64字符串:" + encode);
    }

运行结果:

------------------Java原生Base64编码校验--------------------------
原始字符串:Alian
Java原生编码后的base64字符串:QWxpYW4=

由此可见,我们的编译流程得出的结果和Java原生得到的结果是一致的,解码流程就反过来就行了。

三、Base64工具类

来来来,直接上工具类,进行测试。

Base64Util.java

package com.alian.csdn.utils;

/**
 * @program: CSDN
 * @description: Base64工具类
 * @author: Alian
 * @create: 2021-06-02 11:20:10
 **/
public final class Base64Util {

    static private final int BASELENGTH = 128;
    static private final int LOOKUPLENGTH = 64;
    static private final int TWENTYFOURBITGROUP = 24;
    static private final int EIGHTBIT = 8;
    static private final int SIXTEENBIT = 16;
    static private final int FOURBYTE = 4;
    static private final int SIGN = -128;
    static private final char PAD = '=';
    static private final boolean fDebug = false;
    static final private byte[] base64Alphabet = new byte[BASELENGTH];
    static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];

    static {
        for (int i = 0; i < BASELENGTH; ++i) {
            base64Alphabet[i] = -1;
        }
        for (int i = 'Z'; i >= 'A'; i--) {
            base64Alphabet[i] = (byte) (i - 'A');
        }
        for (int i = 'z'; i >= 'a'; i--) {
            base64Alphabet[i] = (byte) (i - 'a' + 26);
        }
        for (int i = '9'; i >= '0'; i--) {
            base64Alphabet[i] = (byte) (i - '0' + 52);
        }
        base64Alphabet['+'] = 62;
        base64Alphabet['/'] = 63;
        for (int i = 0; i <= 25; i++) {
            lookUpBase64Alphabet[i] = (char) ('A' + i);
        }
        for (int i = 26, j = 0; i <= 51; i++, j++) {
            lookUpBase64Alphabet[i] = (char) ('a' + j);
        }
        for (int i = 52, j = 0; i <= 61; i++, j++) {
            lookUpBase64Alphabet[i] = (char) ('0' + j);
        }
        lookUpBase64Alphabet[62] = '+';
        lookUpBase64Alphabet[63] = '/';
    }

    private static boolean isWhiteSpace(char octect) {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }

    private static boolean isPad(char octect) {
        return (octect == PAD);
    }

    private static boolean isData(char octect) {
        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
    }

    /**
     * 将十六进制八位字节编码为Base64
     *
     * @param binaryData 包含二进制数据的数组
     * @return 编码Base64字符串
     */
    public static String encode(byte[] binaryData) {
        if (binaryData == null) {
            return null;
        }
        int lengthDataBits = binaryData.length * EIGHTBIT;
        if (lengthDataBits == 0) {
            return "";
        }
        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
        char[] encodedData = new char[numberQuartet * 4];
        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        if (fDebug) {
            System.out.println("number of triplets = " + numberTriplets);
        }
        for (int i = 0; i < numberTriplets; i++) {
            b1 = binaryData[dataIndex++];
            b2 = binaryData[dataIndex++];
            b3 = binaryData[dataIndex++];
            if (fDebug) {
                System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
            }
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
            if (fDebug) {
                System.out.println("val2 = " + val2);
                System.out.println("k4   = " + (k << 4));
                System.out.println("vak  = " + (val2 | (k << 4)));
            }
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
        }
        if (fewerThan24bits == EIGHTBIT) {
            b1 = binaryData[dataIndex];
            k = (byte) (b1 & 0x03);
            if (fDebug) {
                System.out.println("b1=" + b1);
                System.out.println("b1<<2 = " + (b1 >> 2));
            }
            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
            encodedData[encodedIndex++] = PAD;
            encodedData[encodedIndex++] = PAD;
        } else if (fewerThan24bits == SIXTEENBIT) {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
            encodedData[encodedIndex++] = PAD;
        }
        return new String(encodedData);
    }

    /**
     * 将Base64数据解码为八位字节
     *
     * @param encoded 包含Base64数据的字符串
     * @return 包含解码数据的数组.
     */
    public static byte[] decode(String encoded) {
        if (encoded == null) {
            return null;
        }
        char[] base64Data = encoded.toCharArray();
        //删除空白
        int len = removeWhiteSpace(base64Data);
        //应该可以被四整除
        if (len % FOURBYTE != 0) {
            return null;
        }
        int numberQuadruple = (len / FOURBYTE);
        if (numberQuadruple == 0) {
            return new byte[0];
        }
        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
        int i = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        byte[] decodedData = new byte[(numberQuadruple) * 3];
        for (; i < numberQuadruple - 1; i++) {
            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
                    || !isData((d3 = base64Data[dataIndex++]))
                    || !isData((d4 = base64Data[dataIndex++]))) {
                return null;
            }//没有数据直接返回null
            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
        }
        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {
            return null;没有数据直接返回null
        }
        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];
        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData((d3)) || !isData((d4))) {
            //检查是否为填充字符
            if (isPad(d3) && isPad(d4)) {
                if ((b2 & 0xf) != 0) {//最后四位应为0
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 1];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                return tmp;
            } else if (!isPad(d3) && isPad(d4)) {
                b3 = base64Alphabet[d3];
                if ((b3 & 0x3) != 0){//最后2位应为零
                    return null;
                }
                byte[] tmp = new byte[i * 3 + 2];
                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                return tmp;
            } else {
                return null;
            }
        } else { //No PAD e.g 3cQl
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
        }
        return decodedData;
    }

    /**
     * 从包含编码Base64数据的MIME中删除空白
     *
     * @param data base64数据的字节数组(带空白)
     * @return 新的长度
     */
    private static int removeWhiteSpace(char[] data) {
        if (data == null) {
            return 0;
        }
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i])) {
                data[newSize++] = data[i];
            }
        }
        return newSize;
    }
}

四、实践

对于Base64的编码和解码我一般是推荐使用:java.util.Base64

java.util.Base64

    /**
     * Java原生Base64编码和解码
     * 此处单元测试的注解是采用:org.junit.Test
     */
    @Test
    public void javaBase64(){
        System.out.println("------------------Java原生Base64编码、解码--------------------------");
        //定义要编码的字符串
        String plainText="https://blog.csdn.net/Alian_1223";
        System.out.println("原始字符串:"+plainText);
        System.out.println("原始字符串长度:"+plainText.length());
        //获取Java原生的Base64编码对象(java.util.Base64.getEncoder())
        String encode = Base64.getEncoder().encodeToString(plainText.getBytes(StandardCharsets.UTF_8));
        System.out.println("Java原生编码后的base64字符串:"+encode);
        System.out.println("Java原生编码后的base64字符串长度:"+encode.length());
        //获取Java原生的Base64解码密对象(java.util.Base64.getDecoder())
        byte[] decode = Base64.getDecoder().decode(encode);
        System.out.println("Java原生解码后的字符串:"+new String(decode));
        System.out.println("Java原生解码后的字符串长度:"+new String(decode).length());
    }

运行结果:

------------------Java原生Base64编码、解码--------------------------
原始字符串:https://blog.csdn.net/Alian_1223
原始字符串长度:32
Java原生编码后的base64字符串:aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FsaWFuXzEyMjM=
Java原生编码后的base64字符串长度:44
Java原生解码后的字符串:https://blog.csdn.net/Alian_1223
Java原生解码后的字符串长度:32

Base64Util.java

既然我们的工具类也写好了,我们也测试一下我们的工具类Base64Util

    /**
     * Base64Util编码和解码
     * 此处单元测试的注解是采用:org.junit.Test
     */
    @Test
    public void base64Util(){
        System.out.println("------------------Base64Util编码、解码--------------------------");
        String plainText="https://blog.csdn.net/Alian_1223";
        System.out.println("原始字符串:"+plainText);
        System.out.println("原始字符串长度:"+plainText.length());
        //直接调用encode方法
        String encode = Base64Util.encode(plainText.getBytes(StandardCharsets.UTF_8));
        System.out.println("Base64Util编码后的base64字符串:"+encode);
        System.out.println("Base64Util编码后的base64字符串长度:"+encode.length());
        //直接调用decode方法
        byte[] decode = Base64Util.decode(encode);
        System.out.println("Base64Util解码后的字符串:"+new String(decode));
        System.out.println("Base64Util解码后的字符串长度:"+new String(decode).length());
    }

运行结果:

------------------Base64Util编码、解码--------------------------
原始字符串:https://blog.csdn.net/Alian_1223
原始字符串长度:32
Base64Util编码后的base64字符串:aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FsaWFuXzEyMjM=
Base64Util编码后的base64字符串长度:44
Base64Util解码后的字符串:https://blog.csdn.net/Alian_1223
Base64Util解码后的字符串长度:32

  不管是使用Java原生的Base64,还是使用我们自己的工具类,结果都是一样的。但是Java原生Base64工具是从JDK1.8开始加的,如果你的环境低于JDK1.8的话,比如1.6,还是可以使用我们的工具类Base64Util来实现编码和解码的。Base64编码之后的文本,要比原文大约三分之一,同时如果是sun.misc.BASE64Encoder还可能出现换行的情况,大家也要注意点。

结语

  以上就是今天要讲的内容,本文简单介绍了Base64,并编写了一个Base64Util工具类,用Java原生的Base64及我们的工具类都实现了Base64的编码和解码,但是我还是建议大家使用Java原生的【java.util.Base64】工具类,开箱即用,并且还减少了程序的代码量。如果觉得对你有帮助,欢迎大家评论交流。

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java中,可以使用Base64编码对数据进行加密和解密。以下是一个示例的Java Base64加解密工具类: ```java import java.util.Base64; public class Base64Utils { public static String encode(String data) { byte[] bytes = data.getBytes(); byte[] encodedBytes = Base64.getEncoder().encode(bytes); return new String(encodedBytes); } public static String decode(String data) { byte[] bytes = data.getBytes(); byte[] decodedBytes = Base64.getDecoder().decode(bytes); return new String(decodedBytes); } public static void main(String[] args) { String originalData = "Hello, World!"; String encodedData = encode(originalData); String decodedData = decode(encodedData); System.out.println("原始数据: " + originalData); System.out.println("加密后的数据: " + encodedData); System.out.println("解密后的数据: " + decodedData); } } ``` 在上面的示例中,`encode`方法用于将字符串进行Base64编码,而`decode`方法用于将Base64编码的字符串进行解码。两个方法的返回值均为字符串类型。 在`main`方法中,我们可以利用这两个方法来测试加解密的功能。首先,将原始数据字符串传入`encode`方法进行编码,得到加密后的数据字符串;然后,将加密后的数据字符串传入`decode`方法进行解码,得到解密后的数据字符串。 最后,通过使用`System.out.println()`方法将原始数据、加密后的数据和解密后的数据打印出来,以便观察加解密的效果。 需要注意的是,这里使用的是Java 8中的`java.util.Base64`类,该类提供了编码解码的方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值