Base64的编码与解码的实现方法(超详细,每一行代码都含注释)

14 篇文章 1 订阅
9 篇文章 0 订阅

        Base64(基底64)是一种基于64个可打印字符来表示二进制数据的表示方法。每6个比特为一个单元,对应某个可打印字符。3个字节相当于24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。在Base64中的可打印字符包括字母A-Za-z、数子0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后BinHex的版本使用不同的64字符集来代表6个二进制数字,但是不被称为Base64。

        Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。

 

 

         介绍完Base64之后,下面来看看我的实现代码:

        编码的实现代码如下:

 /**
     * 编码方法
     * @param str 字符串
     * @return 返回编码后的字符串
     */
    public static String toBase64(String str) {
        //把str按字符放入bytes数组
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        //记录需要补等号的个数
        int count = 3 - (bytes.length % 3);
        //记录数组长度
        int length = bytes.length;
        //下标指针
        int index = 0;
        //定义一个StringBuilder来存放编码后的字符串
        StringBuilder sb = new StringBuilder();
        while((length - index) >= 3) {
            //当数组长度比下标指针相差3甚至更多时,就将bytes[index],bytes[index + 1],bytes[index + 2]
            // (每一个bytes[]都由8位二进制数组成)拼接成24位二进制数
            int v = (bytes[index] & 0xFF) << 16 | (bytes[index + 1] & 0xFF) << 8 | (bytes[index + 2] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移18位,取6位
            sb.append(toBase64[v >>> 18 & 0x3F]);
            //右移12位,取6位
            sb.append(toBase64[v >>> 12 & 0x3F]);
            //右移6位,取6位
            sb.append(toBase64[v >>> 6 & 0x3F]);
            //取6位
            sb.append(toBase64[v & 0x3F]);
            //下标指针加3
            index += 3;
            //如果还满足(length - index) >= 3,取接下来的3个bytes[]进行拼接,不满足则跳出循环
        }

        if (count == 1){
            //如果需要补1个等号
            //bytes[index],bytes[index + 1]拼接成16位二进制数
            int v = (bytes[index] & 0xFF) << 8 | (bytes[index + 1] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移10位,取6位
            sb.append(toBase64[v >>> 10 & 0x3F]);
            //右移4位,取6位
            sb.append(toBase64[v >>> 4 & 0x3F]);
            //左移2位(相当于需要借2位),取6位
            sb.append(toBase64[v << 2 & 0x3F]);
            sb.append('=');
        }else if (count == 2){
            //如果需要补2个等号
            //bytes[index]化成8位二进制数
            int v = (bytes[index] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移2位,取6位
            sb.append(toBase64[v >>> 2 & 0x3F]);
            //左移4位(相当于需要借4位),取6位
            sb.append(toBase64[v << 4 & 0x3F]);
            sb.append('=');
            sb.append('=');
        }
        return sb.toString();
    }

        解码的实现代码如下:

/**
     * 解码方法
     * @param str 字符串
     * @return 返回解码后的字符串
     */
    public static String reversalBase64(String str) {
        //记录=的数量
        int count = 0;
        //arr下标指针
        int index = 0;
        //bytes下标指针
        int indexs = 0;
        //遍历字符串得到=的数量
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == '=') {
                count++;
            }
        }
        //new一个arr数组用来存放非=的字符串
        int length = str.length() - count;
        int[] arr = new int[length];
        //得到arr数组的值所对应的char数组的下标
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < toBase64.length; j++) {
                if (str.charAt(i) == toBase64[j]) {
                    arr[i] = j;
                }
            }
        }
        //new一个bytes数组用来存放解码后的字符串的每一个字符
        byte[] bytes = new byte[str.length() / 4 * 3 - count];
        while ((length / 4) > 0) {
            //当arr数组长度大于等于4时,就将arr[index],arr[index + 1],arr[index + 2],arr[index + 3]
            // (每一个arr[]都由6位二进制数组成)拼接成24位二进制数
            int v = (arr[index] & 0x3F) << 18 | (arr[index + 1] & 0x3F) << 12 | (arr[index + 2] & 0x3F) << 6 | (arr[index + 3] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移16位,取8位
            bytes[indexs] = (byte) (v >>> 16 & 0xFF);
            //右移8位,取8位
            bytes[indexs + 1] = (byte) (v >>> 8 & 0xFF);
            //取8位
            bytes[indexs + 2] = (byte) (v & 0xFF);
            //bytes下标指针加3
            indexs += 3;
            //arr下标指针加4
            index += 4;
            //arr数组长度减4
            length -= 4;
            //如果还满足(length / 4) > 0,取接下来的4个arr[]进行拼接,不满足则跳出循环
        }

        if (count == 1) {
            //如果存在1个=
            //将arr[index],arr[index + 1],arr[index + 2]拼接成18位二进制数
            int v = (arr[index] & 0x3F) << 12 | (arr[index + 1] & 0x3F) << 6 | (arr[index + 2] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移10位,取8位
            bytes[indexs] = (byte) (v >>> 10 & 0xFF);
            //右移2位,取8位
            bytes[indexs + 1] = (byte) (v >>> 2 & 0xFF);
        } else if (count == 2) {
            //如果存在2个=
            //将arr[index],arr[index + 1]拼接成12位二进制数
            int v = (arr[index] & 0x3F) << 6 | (arr[index + 1] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移4位,取8位
            bytes[indexs] = (byte) (v >>> 4 & 0xFF);
        }
        //将bytes数组中存的字符转换成String类型
        String result = new String(bytes, StandardCharsets.UTF_8);
        return result;
    }

        总代码含测试代码和结果如下:

package practice;

import java.nio.charset.StandardCharsets;

public class Base64 {

    //用一个char数组封装base64码
    private static final char[] toBase64 = {
            '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', '+', '/'
    };

    public static void main(String[] args) {
        String str = "好好学习";
        System.out.println("编码前:"+str);
        str = toBase64(str);
        System.out.println("编码后:"+str);
        str = reversalBase64(str);
        System.out.println("解码后:"+str);
    }

    /**
     * 编码方法
     * @param str 字符串
     * @return 返回编码后的字符串
     */
    public static String toBase64(String str) {
        //把str按字符放入bytes数组
        byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
        //记录需要补等号的个数
        int count = 3 - (bytes.length % 3);
        //记录数组长度
        int length = bytes.length;
        //下标指针
        int index = 0;
        //定义一个StringBuilder来存放编码后的字符串
        StringBuilder sb = new StringBuilder();
        while((length - index) >= 3) {
            //当数组长度比下标指针相差3甚至更多时,就将bytes[index],bytes[index + 1],bytes[index + 2]
            // (每一个bytes[]都由8位二进制数组成)拼接成24位二进制数
            int v = (bytes[index] & 0xFF) << 16 | (bytes[index + 1] & 0xFF) << 8 | (bytes[index + 2] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移18位,取6位
            sb.append(toBase64[v >>> 18 & 0x3F]);
            //右移12位,取6位
            sb.append(toBase64[v >>> 12 & 0x3F]);
            //右移6位,取6位
            sb.append(toBase64[v >>> 6 & 0x3F]);
            //取6位
            sb.append(toBase64[v & 0x3F]);
            //下标指针加3
            index += 3;
            //如果还满足(length - index) >= 3,取接下来的3个bytes[]进行拼接,不满足则跳出循环
        }

        if (count == 1){
            //如果需要补1个等号
            //bytes[index],bytes[index + 1]拼接成16位二进制数
            int v = (bytes[index] & 0xFF) << 8 | (bytes[index + 1] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移10位,取6位
            sb.append(toBase64[v >>> 10 & 0x3F]);
            //右移4位,取6位
            sb.append(toBase64[v >>> 4 & 0x3F]);
            //左移2位(相当于需要借2位),取6位
            sb.append(toBase64[v << 2 & 0x3F]);
            sb.append('=');
        }else if (count == 2){
            //如果需要补2个等号
            //bytes[index]化成8位二进制数
            int v = (bytes[index] & 0xFF);
            //每6位为一组转化成十进制数,然后把找到char[十进制数]对应的值放入StringBuilder
            //右移2位,取6位
            sb.append(toBase64[v >>> 2 & 0x3F]);
            //左移4位(相当于需要借4位),取6位
            sb.append(toBase64[v << 4 & 0x3F]);
            sb.append('=');
            sb.append('=');
        }
        return sb.toString();
    }

    /**
     * 解码方法
     * @param str 字符串
     * @return 返回解码后的字符串
     */
    public static String reversalBase64(String str) {
        //记录=的数量
        int count = 0;
        //arr下标指针
        int index = 0;
        //bytes下标指针
        int indexs = 0;
        //遍历字符串得到=的数量
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == '=') {
                count++;
            }
        }
        //new一个arr数组用来存放非=的字符串
        int length = str.length() - count;
        int[] arr = new int[length];
        //得到arr数组的值所对应的char数组的下标
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < toBase64.length; j++) {
                if (str.charAt(i) == toBase64[j]) {
                    arr[i] = j;
                }
            }
        }
        //new一个bytes数组用来存放解码后的字符串的每一个字符
        byte[] bytes = new byte[str.length() / 4 * 3 - count];
        while ((length / 4) > 0) {
            //当arr数组长度大于等于4时,就将arr[index],arr[index + 1],arr[index + 2],arr[index + 3]
            // (每一个arr[]都由6位二进制数组成)拼接成24位二进制数
            int v = (arr[index] & 0x3F) << 18 | (arr[index + 1] & 0x3F) << 12 | (arr[index + 2] & 0x3F) << 6 | (arr[index + 3] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移16位,取8位
            bytes[indexs] = (byte) (v >>> 16 & 0xFF);
            //右移8位,取8位
            bytes[indexs + 1] = (byte) (v >>> 8 & 0xFF);
            //取8位
            bytes[indexs + 2] = (byte) (v & 0xFF);
            //bytes下标指针加3
            indexs += 3;
            //arr下标指针加4
            index += 4;
            //arr数组长度减4
            length -= 4;
            //如果还满足(length / 4) > 0,取接下来的4个arr[]进行拼接,不满足则跳出循环
        }

        if (count == 1) {
            //如果存在1个=
            //将arr[index],arr[index + 1],arr[index + 2]拼接成18位二进制数
            int v = (arr[index] & 0x3F) << 12 | (arr[index + 1] & 0x3F) << 6 | (arr[index + 2] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移10位,取8位
            bytes[indexs] = (byte) (v >>> 10 & 0xFF);
            //右移2位,取8位
            bytes[indexs + 1] = (byte) (v >>> 2 & 0xFF);
        } else if (count == 2) {
            //如果存在2个=
            //将arr[index],arr[index + 1]拼接成12位二进制数
            int v = (arr[index] & 0x3F) << 6 | (arr[index + 1] & 0x3F);
            //每8位为一组转化成byte型,并赋值给bytes
            //右移4位,取8位
            bytes[indexs] = (byte) (v >>> 4 & 0xFF);
        }
        //将bytes数组中存的字符转换成String类型
        String result = new String(bytes, StandardCharsets.UTF_8);
        return result;
    }

}

        如果你有哪里看不懂的请在评论区与我交流 ,或者你有更好的见解也可以与我交流。

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欲戴王冠♛必承其重

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值