优雅地实现base64字符串的解码,涉及到正则表达式的分组,NIO和jdk1.8的Base64

前言

最近用到了一款移动端的裁剪插件 PhotoClip(https://github.com/baijunjie/PhotoClip.js),移动端裁剪之后的图片以base64编码的形式传给后端,后端要对base64进行解码转存成文件存储,基于这个业务需求,实现了一个简单的工具类。

其实,网上有很多差不多的代码,只是稍微有点不同。参考别人的代码,自己写出来可能更能让自己满意吧。好,进入正题。

分析

1、如果不使用其他类库。早期(在jdk1.8以前)在Java上做Base64的编码与解码,会使用到JDK里sun.misc套件下的BASE64Encoder和BASE64Decoder这两个类。在jdk1.8,java.util套件中,新增了Base64这个类,可以用来处理Base64的编码与解码。相信很多人使用SpringBoot 2.x也会用到Spring提供的Base64Utils工具类,它底层也是使用了jdk1.8的Base64这个类。为了工具类更为通用,我们就直接使用原生的jdk1.8的API。

2、基于常见图片的base64编码格式,我们写一个较为严格的正则表达式来校验格式。并通过正则表达式的分组功能(jdk提供了Pattern和Matcher两个类),将图片后缀名和数据部分从base64字符串取出来。相信很多人都没接触过java与正则表达式相关的API。只知道字符串类里面有些方法传参可以是正则表达式,其实java.util.regex包提供了更为强大的正则表达式支持。当然,要使用这些API,需要对正则表达式有简单的了解,当然也不需要很精通。毕竟正则表达式也是一门不小的学问。用啥学啥呗。

3、关于流的拷贝,我估计很多人也会直接使用bio的形式,就是循环加buf数组的形式,当然这个模板代码,其实也可以封装成工具方法。在这里,我们就不另外封装了。因为其实,在nio中的channel相关的API封装了这样功能的方法。我们只需要将bio的流转成channel就可以了。

一个简简单单的工具方法,可以学习到了jdk中我们几乎没用过的API。所以,一些书或者视频教程总是标榜“从入门到精通”,其实都是标题党和耍流氓,光介绍一些常见API,很多API和一些新增特性都没有谈到,又谈何去了解jdk底层呢。多的不说了,给一句话共勉吧:任何学问的学习都是“路漫漫其修远兮,吾将上下而求索”,要始终抱着谦虚和务实的心态

代码

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author passerbyYSQ
 * @create 2021-01-31 1:34
 */
public class Base64Utils {

    // 匹配常见图片的base64编码的正则表达式
    private static final Pattern pattern = Pattern.compile("^(data:image/(jpg|jpeg|png);base64,)(\\S+)");

    /**
     * 将base64编码转成文件保存
     * @param base64Data    完整的base64编码
     * @param destDir       目标目录
     * @return
     */
    public static boolean base64ToFile(String base64Data, File destDir, String fileName) {
        Matcher matcher = pattern.matcher(base64Data);
        if (!matcher.find()) {
            return false;
        }
        if (!destDir.exists()) {
            destDir.mkdirs();
        }

        // 取出分组信息,必须要在matcher.find()==true之后
        String suffix = matcher.group(2); // 取出图片的后缀
        String data = matcher.group(3); // 取出数据部分

        File tmpFile = new File(destDir, fileName + "." + suffix);
        byte[] bytes = Base64.getDecoder().decode(data);

        // 流的拷贝,可以使用原始的bio方式。在这里使用nio的通道相关的API来操作
        ReadableByteChannel inChannel = Channels.newChannel(new ByteArrayInputStream(bytes));
        FileChannel outChannel = null;
        try {
            outChannel = new FileOutputStream(tmpFile, true).getChannel();
            outChannel.transferFrom(inChannel, outChannel.size(), bytes.length);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            CloseUtils.close(inChannel, outChannel);
        }
    }

    /**
     * 将bas364编码转成byte[]
     * @param base64Data
     * @return
     */
    public static byte[] base64ToBytes(String base64Data) {
        Matcher matcher = pattern.matcher(base64Data);
        if (!matcher.find()) {
            return null;
        }
        String data = matcher.group(3); // 取出data部分
        return Base64.getDecoder().decode(data);
    }
}

 


版权声明:本文为qq_43290318原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。