Java8 终于官方提供了 Base64 编码/解码的支持(见 java.util.Base64 类)。该类完全由静态方法组成,用于获取 Base64 编码方案的编码器和解码器。该类的实现支持 RFC 4648 和 RFC 2045 中指定的以下 Base64 类型。
Basic:使用 RFC 4648 和 RFC 2045 表 1 中指定的 “Base64字母表” 进行编码和解码操作。编码器不添加任何换行(分隔符)字符。解码器拒绝包含 Base64 字母表以外字符的数据。
URL和文件名安全:使用 RFC 4648 表 2 中指定的 “URL 和文件名安全 Base64 字母表” 进行编码和解码。编码器不添加任何换行(行分隔符)字符。解码器拒绝包含 Base64 字母表以外字符的数据。
MIME:使用 RFC 2045 表 1 中指定的 “Base64字母表” 进行编码和解码操作。编码输出必须以每行不超过 76 个字符的行表示,并使用回车符 “\r” 和紧跟其后的换行符 “\n” 作为行分隔符。编码输出的末尾不添加分隔符。在解码操作中,所有分隔符或其他不在 base64 字母表中的字符都将被忽略。
Base64 编码可以将一组字节序列编码为一个可打印的 ASCII 字符序列。它经常用于电子邮件消息中的二进制数据,以及 “基本的” HTTP 认证。在过去的很多年中,JDK 都只有一个未公开的类 java.util.prefs.Base64, 以及一个没有文档描述的类 sun.misc.BASE64Encoder。终于,Java8 提供了一个标准的编码器和解码器。
Base64 编码使用 64 个字符来编码 6bit 信息:
26 个大写字母 A-Z。
26 个小写字母 a-z。
10 个数字 0-9。
2 个符号 + 和 - 或者 - 和 _ (对于 URL 和文件名来说都是安全的)。
一般来说,编码后的字符串没有换行符,但是电子邮件使用的 MIME 标准要求每 76 个字符要使用一个 "\r\n" 换行符。
要进行 Base64 编码,可以使用 Base64 类的静态方法 getEncoder, getUrlEncoder, 或者 getMimeEncoder 来获得一个 Base64.Encoder 对象。该类包含了用来对字符数组或者 NIO ByteBuffer 进行编码的方法。例如:
package com.hxstrive.jdk8.base64; import java.util.Base64; public class Base64Demo1 { public static void main(String[] args) { String str = "Hello World!"; Base64.Encoder encoder = Base64.getEncoder(); // 编码 byte[] result = encoder.encode(str.getBytes()); System.out.println(new String(result)); //SGVsbG8gV29ybGQh // 编码(字符串) String result2 = encoder.encodeToString(str.getBytes()); System.out.println(result2); //SGVsbG8gV29ybGQh } }
另外,你可以使用 wrap 方法去 “包装” 一个输出流,这样所有发送给包装流的数据都会自动进行编码。例如,对 ByteArrayOutputStream 进行包装,将所有数据输入到包装后的 OutputStream 中,最后从 ByteArrayOutputStream 中获取编码后的数据,代码如下:
Base64.Encoder encoder = Base64.getEncoder(); // 包装一个输出流 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); OutputStream outputStream = encoder.wrap(byteArrayOutputStream); // 写入数据到输出流中 String str = "Hello World!"; // 注意:写入到包装流中,它是对我们的 ByteArrayOutputStream 进行包装 outputStream.write(str.getBytes()); // 依然从 ByteArrayOutputStream 中获取数据,而不是包装流 System.out.println(new String(byteArrayOutputStream.toByteArray())); // SGVsbG8gV29ybGQh
如果要进行 Base64 解码,只需将这些操作颠倒过来,例如:
Base64.Decoder decoder = Base64.getDecoder(); byte[] result = decoder.decode("SGVsbG8gV29ybGQh"); System.out.println(new String(result)); // Hello World! byte[] reuslt2 = decoder.decode("SGVsbG8gV29ybGQh".getBytes()); System.out.println(new String(reuslt2)); // Hello World!
或者
Base64.Decoder decoder = Base64.getDecoder(); // 包装流 InputStream input = decoder.wrap(new ByteArrayInputStream("SGVsbG8gV29ybGQh".getBytes())); // 从包装流读取解码的数据 BufferedInputStream in = new BufferedInputStream(input); byte[] buffer = new byte[in.available()]; if(-1 != in.read(buffer, 0, buffer.length)) { System.out.println(new String(buffer)); // Hello World! }
简单用法如下:
String str = "https://www.hxstrive.com"; // 编码 Base64.Encoder encoder = Base64.getUrlEncoder(); byte[] encoderResult = encoder.encode(str.getBytes()); System.out.println("编码结果:" + new String(encoderResult)); //编码结果:aHR0cHM6Ly93d3cuaHhzdHJpdmUuY29t // 解码 Base64.Decoder decoder = Base64.getUrlDecoder(); byte[] decoderResult = decoder.decode(encoderResult); System.out.println("解码结果:" + new String(decoderResult)); //解码结果:https://www.hxstrive.com
简单用法如下:
String str = "使用 RFC 4648 表 2 中指定的 “URL 和文件名安全 Base64 字母表” 进行编码和解码。" + "编码器不添加任何换行(行分隔符)字符。解码器拒绝包含 Base64 字母表以外字符的数据。"; // 编码 Base64.Encoder encoder = Base64.getMimeEncoder(); byte[] encoderResult = encoder.encode(str.getBytes()); System.out.println("编码结果:" + new String(encoderResult)); //编码结果:5L2/55SoIFJGQyA0NjQ4IOihqCAyIOS4reaMh+WumueahCDigJxVUkwg5ZKM5paH5Lu25ZCN5a6J //5YWoIEJhc2U2NCDlrZfmr43ooajigJ0g6L+b6KGM57yW56CB5ZKM6Kej56CB44CC57yW56CB5Zmo //5LiN5re75Yqg5Lu75L2V5o2i6KGM77yI6KGM5YiG6ZqU56ym77yJ5a2X56ym44CC6Kej56CB5Zmo //5ouS57ud5YyF5ZCrIEJhc2U2NCDlrZfmr43ooajku6XlpJblrZfnrKbnmoTmlbDmja7jgII= // 解码 Base64.Decoder decoder = Base64.getMimeDecoder(); byte[] decoderResult = decoder.decode(encoderResult); System.out.println("解码结果:" + new String(decoderResult)); //解码结果:使用 RFC 4648 表 2 中指定的 “URL 和文件名安全 Base64 字母表” 进行编码和解码。编码器不添加任何换行(行分隔符)字符。解码器拒绝包含 Base64 字母表以外字符的数据。