关于java:netty系列之java中的base64编码器

45次阅读

共计 3731 个字符,预计需要花费 10 分钟才能阅读完成。

简介

什么是 Base64 编码呢?在答复这个问题之前,咱们须要理解一下计算机中文件的分类,对于计算机来说文件能够分为两类,一类是文本文件,一类是二进制文件。

对于二进制文件来说,其内容是用二进制来示意的,对于人类是不可立马了解的。如果你尝试用文本编辑器关上二进制文件,可能会看到乱码。这是因为二进制文件的编码方式和文本文件的编码方式是不一样的,所以当文本编辑器尝试将二进制文件翻译成为文本内容的时候,就会呈现乱码。

对于文本文件来说,也有很多种编码方式,比方最早的 ASCII 编码和目前罕用的 UTF- 8 和 UTF-16 等编码方式。即便是文本文件,如果你应用不同的编码方式关上,也可能会看到乱码。

所以不论是文本文件还是二进制文件也好,都须要进行编码格局的对立。也就是说写入的编码是什么样子的,那么数据读取的编码也应该和其匹配。

Base64 编码实际上就是将二进制数据编码成为可视化 ASCII 字符的一种编码方式。

为什么会有这样的要求呢?

咱们晓得计算机世界的倒退不是欲速不达的,它是一个缓缓成长的过程,对于字符编码来说,最早只反对 ASCII 编码,前面才扩大到 Unicode 等。所以对于很多利用来说除了 ASCII 编码之外的其余编码格局是不反对的,那么如何在这些零碎中展现非 ASCII code 呢?

解决的形式就是进行编码映射,将非 ASCII 的字符映射成为 ASCII 的字符。而 base64 就是这样的一种编码方式。

常见的应用 Base64 的中央就是在 web 网页中,有时候咱们须要在网页中展现图片,那么能够将图片进行 base64 编码,而后填充到 html 中。

还有一种利用就是将文件进行 base64 编码,而后作为邮件的附件进行发送。

JAVA 对 base64 的反对

既然 base64 编码这么好用,接下来咱们来看一下 JAVA 中的 base64 实现。

java 中有一个对应的 base64 实现,叫做 java.util.Base64。这个类是 Base64 的工具类,是 JDK 在 1.8 版本引入的。

Base64 中提供了三个 getEncoder 和 getDecoder 办法,通过获取对应的 Encoder 和 Decoder,而后就能够调用 Encoder 的 encode 和 decode 办法对数据进行编码和解码,十分的不便。

咱们先来看一下 Base64 的根本应用例子:

 // 应用 encoder 进行编码
 String encodedString = Base64.getEncoder().encodeToString("what is your name baby?".getBytes("utf-8"));
 System.out.println("Base64 编码过后的字符串 :" + encodedString);

 // 应用 encoder 进行解码
 byte[] decodedBytes = Base64.getDecoder().decode(encodedString);

 System.out.println("解码过后的字符串:" + new String(decodedBytes, "utf-8"));

作为一个工具类,JDK 中提供的 Base64 工具类还是很好用的。

这里就不具体解说它的应用,本篇文章次要剖析 JDK 中 Base64 是怎么实现的。

JDK 中 Base64 的分类和实现

JDK 中 Base64 类有提供了三个 encoder 办法,别离是 getEncoder,getUrlEncoder 和 getMimeEncoder:

    public static Encoder getEncoder() {return Encoder.RFC4648;}

    public static Encoder getUrlEncoder() {return Encoder.RFC4648_URLSAFE;}

    public static Encoder getMimeEncoder() {return Encoder.RFC2045;}

同样的,它也提供了三个对应的 decoder,别离是 getDecoder,getUrlDecoder,getMimeDecoder:

    public static Decoder getDecoder() {return Decoder.RFC4648;}

    public static Decoder getUrlDecoder() {return Decoder.RFC4648_URLSAFE;}

    public static Decoder getMimeDecoder() {return Decoder.RFC2045;}

从代码中能够看出,这三种编码别离对应的是 RFC4648,RFC4648_URLSAFE 和 RFC2045。

这三种都属于 base64 编码的变体,咱们看下他们有什么区别:

编码名称 编码字符 编码字符 编码字符
第 62 位 第 63 位 补全符
RFC 2045: Base64 transfer encoding for MIME + / = mandatory
RFC 4648: base64 (standard) + / = optional
RFC 4648: base64url (URL- and filename-safe standard) - _ = optional

能够看到 base64 和 Base64url 的区别是第 62 位和第 63 位的编码字符不一样,而 base64 for MIME 跟 base64 的区别是补全符是否是强制的。

另外,对于 Basic 和 base64url 来说,不会增加 line separator 字符,而 base64 for MIME 在一行超出 76 字符之后,会增加 ’\r’ 和 ‘\n’ 作为 line separator。

最初,如果在解码的过程中,发现有不存于 Base64 映射表中的字符的解决形式也不一样,base64 和 Base64url 会间接回绝,而 base64 for MIME 则会疏忽。

base64 和 Base64url 的区别能够通过上面两个办法来看出:

        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', '+', '/'
        };
        private static final char[] toBase64URL = {
            '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', '-', '_'
        };

而对 MIME 来说,定义了一个一行的最大字符个数, 和换行符:

        private static final int MIMELINEMAX = 76;
        private static final byte[] CRLF = new byte[] {'\r', '\n'};

Base64 的高级用法

个别状况下咱们用 Base64 进行编码的对象长度是固定的,咱们只须要将输出对象转换成为 byte 数组即可调用 encode 或者 decode 的办法。

然而在某些状况下咱们须要对流数据进行转换,这时候就能够用到 Base64 中提供的两个对 Stream 进行 wrap 的办法:

        public OutputStream wrap(OutputStream os) {Objects.requireNonNull(os);
            return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
                                       newline, linemax, doPadding);
        }
        public InputStream wrap(InputStream is) {Objects.requireNonNull(is);
            return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
        }

这两个办法别离对应于 encoder 和 decoder。

总结

以上就是 JDK 中对 Base64 的实现和应用,尽管 base64 的变种有很多种,然而 JDK 中的 Base64 只实现了其中用途最为宽泛的 3 种。大家在应用的时候肯定要辨别具体是那种 Base64 的实现形式,免得呈现问题。

本文已收录于 http://www.flydean.com/14-1-1-java-base64/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

正文完
 0