美文网首页
Java1.8实现Base64编码解码

Java1.8实现Base64编码解码

作者: 骑着乌龟去看海 | 来源:发表于2018-02-08 17:39 被阅读845次

    概述

    首先,我们先来说下什么是Base64编码,然后再来学习下Java中Base64编码的使用。

    历史

      Base64算法最早是为了解决电子邮件传输的问题的,早先的邮件传输协议中只支持ASCII码传递,如果要传输二进制文件,如图片和视频,是无法传输的,而BASE64可以将二进制文件内容编码成为只包含ASCII码的内容,这样就可以传输了。
      Base64算法大家常常说成是加密算法,但准确的来说,Base64不是一种加密算法,只能算是一种基于64个字符的编码算法。

      它有一个字符映射表,每个字符映射了一个十进制编码,共映射了64个字符。Base64将给定的数据经二进制转换后与字符映射表相对应,得到所谓的密文;映射表如下,映射表的最后是一个等号,是作为补位符用来补位的。

    编号 字符 编号 字符 编号 字符 编号 字符
    0 A 16 Q 32 g 48 w
    1 B 17 R 33 h 49 x
    2 C 18 S 34 i 50 y
    3 D 19 T 35 j 51 z
    4 E 20 U 36 k 52 0
    5 F 21 V 37 l 53 1
    6 G 22 W 38 m 54 2
    7 H 23 X 39 n 55 3
    8 I 24 Y 40 o 56 4
    9 J 25 Z 41 p 57 5
    10 K 26 a 42 q 58 6
    11 L 27 b 43 r 59 7
    12 M 28 c 44 s 60 8
    13 N 29 d 45 t 61 9
    14 O 30 e 46 u 62 +
    15 P 31 f 47 v 63 /

    下面我们来看下Base64算法实现的大致步骤:

    1. 将给定的字符串以字符为单位转换为对应的字符编码(如ASCII码);
    2. 将获得的字符编码转换为二进制码;
    3. 对获得的二进制码做分组转换操作,每3个8位二进制码为一组,转换为每4个6位二进制码为一组(不足6位时地位补0).这是一个分组变化的过程,3个8位二进制码和4个6位二进制码的长度都是24位;
    4. 对获得的4个6位二进制补位,向6位二进制码添加2位高位0,组成4个8位二进制码;
    5. 将获得的4个8位二进制码转换位10进制码;
    6. 将获得的十进制码转换位Base64字符表中对应的字符;
    ASCII码字符编码,

    比如,我们对A进行Base64编码:


    ASCII码字符编码.png

      最终生成的编码中有了两个等号,这是因为原文的二进制码不足24位,最后转换为十进制码时也不足4项,这时就需要用等号补位;

      经Base64编码后的字符串最多只会有2个等号,这是因为 余数 = 原文字节数 MOD 3,所以余数只能时0,1,2。通常判别一个字符串是不是Base64编码的第一步操作就是判断这个字符串末尾是不是有等号。这同时也说明,Base64编码后的字符串是以4个字符为单位,其长度只能是4个字符的整数倍。

    非ASCII码字符编码

      ASCII码可以表示十进制范围为0到127的字符,对应二进制范围是00000000~01111111,ASCII码包含了阿拉伯数字,大小写英文字母和一些控制符,但却没有包含中文,因此有了GB2312,GBK和UTF-8等编码。GBK,GB2312用2个字节来表示一个汉字,UTF-8则用3个字节来表示一个汉字。

    例如:对 这个字以UTF-8的形式进行Base64编码;

    非ASCII码字符编码.png
    最终的Base64编码是 5a+G。当然,如果我们不使用UTF-8,而是使用GBK来进行编码,那编码后的结果就不是5a+G了。

    Java中Base64编码使用

      JDK中Base64的实现在JDK1.7之前是没有对外的公共接口的,只有一个非标准实现,位于sun.misc包中,提供BASE64Encoder类和BASE64Decoder类。由于是不对外,所以不建议使用,并且后续JDK版本可能会去掉对这两个类的支持。

      所以说在JDK1.8之前,如果我们要对数据进行Base64编码,一般会借助于第三方的实现,比如Apache Commons包或者Google Guava包。

      但在JDK1.8之后,这个问题就不复存在了。JDK1.8提供了一个完整的类用于实现Base64编码解码,这个类是 java.util.Base64。以后我们如果需要对Base64编码解码,就可以使用这个类来完成了。

    Base64

    我们可以查看下Base64的官方API:https://docs.oracle.com/javase/8/docs/api/
    Base64提供了一套用于获取编码器和解码器的静态方法,其中大致分为三类:

    • Basic编码器
    • URL和文件安全编码器
    • MIME编码器
    Basic编码

    Basic编码是标准的Base64编码,用于处理常规的需求,使用特别简单:

    public static void main(String[] args) throws UnsupportedEncodingException {
        String string = "密";
        System.out.println("old string: " + string);
        String base64 = Base64.getEncoder().encodeToString(string.getBytes("UTF-8"));
        System.out.println("base64 decode: " + base64);
    
        byte[] bytes = Base64.getDecoder().decode(base64);
        System.out.println("base64 encode: " + new String(bytes, "UTF-8"));
    }
    

    output:

    old string: 密
    base64 decode: 5a+G
    base64 encode: 密
    
    URL编码

    URL编码和Basic编码有些不同,主要是URL中反斜杠 /有特殊的含义,直接编码会不太安全,所以URL编码会使用下划线 _ 来替代 /
    比如我们直接编码:

    String string = "http://www.google.com/index.html?pageNum=1&pageSize=10";
    System.out.println("old string: " + string);
    String base64 = Base64.getEncoder().encodeToString(string.getBytes("UTF-8"));
    System.out.println("base64 decode: " + base64);
    

    output:

    old string: http://www.google.com/index.html?pageNum=1&pageSize=10
    base64 decode: aHR0cDovL3d3dy5nb29nbGUuY29tL2luZGV4Lmh0bWw/cGFnZU51bT0xJnBhZ2VTaXplPTEw
    

    所以,我们可以使用Base64中的 Base64.getUrlEncoder()来获取URL编码器,然后再进一步操作。

    String base64 = Base64.getUrlEncoder().encodeToString(string.getBytes("UTF-8"));
    System.out.println("base64 decode: " + base64);
    byte[] bytes = Base64.getUrlDecoder().decode(base64);
    

    output:

    old string: http://www.google.com/index.html?pageNum=1&pageSize=10
    base64 decode: aHR0cDovL3d3dy5nb29nbGUuY29tL2luZGV4Lmh0bWw_cGFnZU51bT0xJnBhZ2VTaXplPTEw
    base64 encode: http://www.google.com/index.html?pageNum=1&pageSize=10
    
    MIME编码

    MIME编码适用于MIME格式数据,编码后每行的输出不超过76个字符,结束符号为\r\n。所谓MIME格式就是文件的表达形式,比如 image/pngvideo/mp4等。
    打印的结果大致如下:

    NDU5ZTFkNDEtMDVlNy00MDFiLTk3YjgtMWRlMmRkMWEzMzc5YTJkZmEzY2YtM2Y2My00Y2Q4LTk5
    ZmYtMTU1NzY0MWM5Zjk4ODA5ZjVjOGUtOGMxNi00ZmVjLTgyZjctNmVjYTU5MTAxZWUyNjQ1MjJj
    NDMtYzA0MC00MjExLTk0NWMtYmFiZGRlNDk5OTZhMDMxZGE5ZTYtZWVhYS00OGFmLTlhMjgtMDM1
    ZjAyY2QxNDUyOWZiMjI3NDctNmI3OC00YjgyLThiZGQtM2MyY2E3ZGNjYmIxOTQ1MDVkOGQtMzIz
    Yi00MDg0LWE0ZmItYzkwMGEzNDUxZTIwOTllZTJiYjctMWI3MS00YmQzLTgyYjUtZGRmYmYxNDA4
    Mjg3YTMxZjMxZmMtYTdmYy00YzMyLTkyNzktZTc2ZDc5ZWU4N2M5ZDU1NmQ4NWYtMDkwOC00YjIy
    LWIwYWItMzJiYmZmM2M0OTBm
    

    同样,获取该编码或解码器也很简单:

    Base64.getMimeEncoder();
    Base64.getMimeDecoder();
    

    本文主要参考自:
    https://docs.oracle.com/javase/8/docs/api/
    Base64 encoding and decoding in Java 8

    相关文章

      网友评论

          本文标题:Java1.8实现Base64编码解码

          本文链接:https://www.haomeiwen.com/subject/eygttftx.html