leftso 2143 0 2018-07-06 18:52:13

文章位置:左搜> 编程技术> 正文

推荐:Base64在线编码、解码yes

一、Java8 base64来源简介

         Java 8将主要用于引入lambdas、streams、新的日期/时间模型,以及将Nashorn JavaScript引擎引入到Java 中。有些人还会记得Java 8引入各种小而有用的功能,好比Base64 API。什么是Base64,我如何使用这个API?这篇文章回答了这些题目。

二、什么是Base64?

Base64是一种二进制到文本编码方案,通过将二进制数据转换为基数-64表示,以可打印的ASCII字符串格式表示二进制数据。每个Base64数字代表正好6位的二进制数据。

Base64用于防止数据在通过信息系统(如电子邮件)传输时被修改,而这些信息系统可能不是8位清理(它们可能包含8位值)。例如,您将图像附加到电子邮件消息,并希望图像到达另一端而不会出现乱码。您的电子邮件软件Base64对图像进行编码并将等效文本插入到邮件中,如下所示:
Content-Disposition: inline;
	filename=IMG_0006.JPG
Content-Transfer-Encoding: base64

/9j/4R/+RXhpZgAATU0AKgAAAAgACgEPAAIAAAAGAAAAhgEQAAIAAAAKAAAAjAESAAMAAAABAAYA
AAEaAAUAAAABAAAAlgEbAAUAAAABAAAAngEoAAMAAAABAAIAAAExAAIAAAAHAAAApgEyAAIAAAAU
AAAArgITAAMAAAABAAEAAIdpAAQAAAABAAAAwgAABCRBcHBsZQBpUGhvbmUgNnMAAAAASAAAAAEA
...
NOMbnDUk2bGh26x2yiJcsoBIrvtPe3muBbTRGMdeufmH+Nct4chUXpwSPk/qK9GtJRMWWVFbZ0JH
I4rf2dkZSbOjt7hhEzwcujA4I7Gust75pYVwAPpXn+kzNLOVYD7xFegWEKPkHsM/pU1F0NKbNS32
o24sSCOlaaFYLUhjky4x9PSsKL5bJsdWkAz3xirH2dZLy1DM2C44zx1FZqL2PTXY/9k=

该图显示该编码图像以其开头/和结尾=。在...表明我还没有为简洁的文字。请注意,此示例或任何其他示例的整个编码比原始二进制数据大约33%。

收件人的电子邮件软件将Base64解码编码的文本图像,以恢复原始的二进制图像。对于此示例,图像将与消息的其余部分一起显示。
 

三、Base64编码和解码

Base64依赖于简单的编码和解码算法。它们使用65个字符的US-ASCII子集,其中前64个字符中的每一个映射到等效的6位二进制序列。这是字母表:
Value Encoding  Value Encoding  Value Encoding  Value Encoding
    0 A            17 R            34 i            51 z
    1 B            18 S            35 j            52 0
    2 C            19 T            36 k            53 1
    3 D            20 U            37 l            54 2
    4 E            21 V            38 m            55 3
    5 F            22 W            39 n            56 4
    6 G            23 X            40 o            57 5
    7 H            24 Y            41 p            58 6
    8 I            25 Z            42 q            59 7
    9 J            26 a            43 r            60 8
   10 K            27 b            44 s            61 9
   11 L            28 c            45 t            62 +
   12 M            29 d            46 u            63 /
   13 N            30 e            47 v
   14 O            31 f            48 w         (pad) =
   15 P            32 g            49 x
   16 Q            33 h            50 y
第65个字符(=)用于将Base64编码的文本填充为整数大小,就像刚才解释的那样.

编码算法接收8位字节的输入流。假定这个流首先排序为最高位:第一位是第一个字节中的高位,第八位是这个字节中的低位,依此类推。

从左到右,这些字节被组织成24位组。每组被视为四个连接的6位组。每个6位组索引为64个可打印字符的数组; 输出结果字符。

当正在编码的数据的末尾有少于24位可用时,零位被添加(在右边)以形成整数个6位组。然后,=可以输出一个或两个填充字符。有两种情况需要考虑:

  • 剩余的一个字节:将四个零位附加到该字节以形成两个6位组。每个组索引数组并输出结果字符。在这两个字符之后,=输出两个填充字符。
  • 剩下的两个字节:将两个零位附加到第二个字节以形成三个6位组。每个组索引数组并输出结果字符。在这三个字符之后,=输出一个填充字符。

让我们考虑三个示例来了解编码算法的工作原理。首先,假设我们希望编码

@!*
Source ASCII bit sequences with prepended 0 bits to form 8-bit bytes:

@        !        *
01000000 00100001 00101010

Dividing this 24-bit group into four 6-bit groups yields the following:

010000 | 000010 | 000100 | 101010

These bit patterns equate to the following indexes:

16 2 4 42

Indexing into the Base64 alphabet shown earlier yields the following encoding:

QCEq
我们将继续缩短输入序列以@!
Source ASCII bit sequences with prepended 0 bits to form 8-bit bytes:

@        !       
01000000 00100001

Two zero bits are appended to make three 6-bit groups:

010000 | 000010 | 000100

These bit patterns equate to the following indexes:

16 2 4

Indexing into the Base64 alphabet shown earlier yields the following encoding:

QCE

An = pad character is output, yielding the following final encoding:

QCE=
最后一个例子将输入序列缩短为@:  
Source ASCII bit sequence with prepended 0 bits to form 8-bit byte:

@       
01000000

Four zero bits are appended to make two 6-bit groups:

010000 | 000000

These bit patterns equate to the following indexes:

16 0

Indexing into the Base64 alphabet shown earlier yields the following encoding:

QA

Two = pad characters are output, yielding the following final encoding:

QA==
解码算法是编码算法的逆向算法。但是,在检测到不在Base64字母表中的字符或填充字符的数量不正确时,可以自由采取适当的措施。
 

四、Base64变体

已经设计了几个Base64变体。某些变体要求将编码的输出流分成多行固定长度,每行不超过一定的长度限制,并且(最后一行除外)通过行分隔符与下一行分隔开(回车\r后跟一个换行符\n)。我描述了Java 8的Base64 API支持的三种变体。查看Wikipedia的Base64条目以获取完整的变体列表。

基本

RFC 4648描述了称为Basic的Base64变体。此变体使用RFC 4648和RFC 2045的表1中所示的Base64字母表(并在本文前面显示)进行编码和解码。编码器将编码的输出流视为一行; 没有行分隔符输出。解码器拒绝包含Base64字母以外的字符的编码。请注意,可以覆盖这些和其他规定。

哑剧

RFC 2045描述了一种称为MIME的Base64变体。该变体使用RFC 2045表1中提供的Base64字母表进行编码和解码。编码输出流被组织成不超过76个字符的行; 每行(除最后一行)通过行分隔符与下一行分隔开。在解码期间,所有行分隔符或Base64字母表中未找到的其他字符都将被忽略。

URL和文件名安全

RFC 4648描述了称为URL和文件名安全的Base64变体。该变体使用RFC 4648表2中提供的Base64字母表进行编码和解码。字母与前面显示的字母相同,只是-替换+_替换/。不输出行分隔符。解码器拒绝包含Base64字母以外的字符的编码。

Base64编码在冗长的二进制数据和HTTP GET请求的上下文中很有用。这个想法是编码这些数据,然后将其附加到HTTP GET URL。如果使用Basic或MIME变体,则编码数据中的任何+/字符必须按照十六进制序列进行URL编码(+变为%2B/变为%2F)。生成的URL字符串会稍微长一些。通过更换+-/_,URL和文件名安全消除了对URL编码器/解码器(和它们的编码值的长度影响)的需要。另外,由于Unix和Windows文件名不能包含,因此当编码数据用于文件名时,此变体很有用/

五、使用Java的Base64 API

爪哇8引入一个Base64 API由所述的java.util.Base64类及其沿EncoderDecoder嵌套static类。Base64介绍了几种static获取编码器和解码器的方法:

  • Base64.Encoder getEncoder():返回Basic变体的编码器。
  • Base64.Decoder getDecoder():返回Basic变体的解码器。
  • Base64.Encoder getMimeEncoder():返回MIME变体的编码器。
  • Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator):返回编码器,修改后的MIME变体lineLength(给出四舍五入到最接近的4的倍数 - 输出在lineLength<= 0 时不会分隔成行)和lineSeparator。它包含RFC 2045表1中提供的任何Base64字母字符java.lang.IllegalArgumentException时抛出lineSeparator。 

    RFC 2045的编码器,这是从noargument getMimeEncoder()方法返回,是相当严格的。例如,该编码器创建76个字符的固定行长度(最后一行除外)的编码文本。如果你想要一个编码器来支持RFC 1421,它表示一个64字符的固定行长度,你需要使用getMimeEncoder(int lineLength, byte[] lineSeparator)

  • Base64.Decoder getMimeDecoder():返回MIME变体的解码器。
  • Base64.Encoder getUrlEncoder():返回URL和Filename Safe变体的编码器。
  • Base64.Decoder getUrlDecoder():返回URL和Filename Safe变体的解码器。

Base64.Encoder介绍了几种用于编码字节序列的线程安全实例方法。将空引用传递给以下方法之一会导致java.lang.NullPointerException

  • byte[] encode(byte[] src):将所有字节编码src到新分配的字节数组中,此方法返回。
  • int encode(byte[] src, byte[] dst):将所有字节编码srcdst(从偏移量0开始)。如果dst不足以保存编码,IllegalArgumentException则抛出。否则,dst返回写入的字节数。
  • ByteBuffer encode(ByteBuffer buffer):将所有剩余的字节编码buffer到新分配的java.nio.ByteBuffer对象中。返回后,buffer其职位将更新到极限; 其限制不会改变。返回的输出缓冲区的位置将为零,其限制将为结果编码字节的数量。
  • String encodeToString(byte[] src):将所有字节编码src为返回的字符串。调用此方法等同于执行new String(encode(src), StandardCharsets.ISO_8859_1)
  • Base64.Encoder withoutPadding():返回与此编码器等效编码的编码器,但不在编码字节数据的末尾添加任何填充字符。
  • OutputStream wrap(OutputStream os):包装输出流以编码字节数据。建议在使用后及时关闭返回的输出流,在此期间,它会将所有可能的剩余字节清除到基础输出流。关闭返回的输出流将关闭基础输出流。

Base64.Decoder提出了几种解码字节序列的线程安全实例方法。将空引用传递给以下方法之一会导致NullPointerException