从 sun.misc.BASE64 迁移到 Java 8 java.util.Base64
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35301409/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Migrating from sun.misc.BASE64 to Java 8 java.util.Base64
提问by Ivo Mori
Question
题
Are the Java 8 java.util.Base64
MIME Encoder and Decoder a drop-in replacementfor the unsupported, internal Java API sun.misc.BASE64Encoder
and sun.misc.BASE64Decoder
?
是Java 8 java.util.Base64
MIME编码器和解码器一个下拉更换为不支持的,内部的Java APIsun.misc.BASE64Encoder
和sun.misc.BASE64Decoder
?
What I think so far and why
到目前为止我的想法以及原因
Based on my investigation and quick tests (see code below) it should be a drop-in replacementbecause
根据我的调查和快速测试(见下面的代码),它应该是一个替代品,因为
sun.misc.BASE64Encoder
based on its JavaDoc is a BASE64 Character encoder as specified in RFC1521. This RFC is part of the MIMEspecification...java.util.Base64
based on its JavaDocUses the "The Base64 Alphabet" as specified in Table 1 of RFC 2045for encoding and decoding operation...under MIME
sun.misc.BASE64Encoder
基于其 JavaDoc 的是RFC1521 中指定的 BASE64 字符编码器。此 RFC 是MIME规范的一部分...java.util.Base64
基于其JavaDoc使用RFC 2045表 1 中指定的“The Base64 Alphabet”进行编码和解码操作......在MIME 下
Assuming no significant changes in the RFC 1521 and 2045 (I could not find any) and based on my quick test using the Java 8 Base64 MIME Encoder/Decoder should be fine.
假设 RFC 1521 和 2045 没有重大变化(我找不到任何变化)并且基于我使用 Java 8 Base64 MIME 编码器/解码器的快速测试应该没问题。
What I am looking for
我在寻找什么
- an authoritative source confirming or disproving the "drop-in replacement" point OR
- a counterexample which shows a case where java.util.Base64 has different behaviour than the sun.misc.BASE64Encoder OpenJDK Java 8 implementation (8u40-b25)(BASE64Decoder) OR
- whatever you think answers above question definitely
- 确认或反驳“直接替换”点的权威来源或
- 一个反例,显示了 java.util.Base64 与 sun.misc.BASE64Encoder OpenJDK Java 8 implementation (8u40-b25)(BASE64Decoder)具有不同行为的情况或
- 无论您认为什么都可以肯定地回答上述问题
For reference
以供参考
My test code
我的测试代码
public class Base64EncodingDecodingRoundTripTest {
public static void main(String[] args) throws IOException {
String test1 = " ~!@#$%^& *()_+=`| }{[]\;: \"?><,./ ";
String test2 = test1 + test1;
encodeDecode(test1);
encodeDecode(test2);
}
static void encodeDecode(final String testInputString) throws IOException {
sun.misc.BASE64Encoder unsupportedEncoder = new sun.misc.BASE64Encoder();
sun.misc.BASE64Decoder unsupportedDecoder = new sun.misc.BASE64Decoder();
Base64.Encoder mimeEncoder = java.util.Base64.getMimeEncoder();
Base64.Decoder mimeDecoder = java.util.Base64.getMimeDecoder();
String sunEncoded = unsupportedEncoder.encode(testInputString.getBytes());
System.out.println("sun.misc encoded: " + sunEncoded);
String mimeEncoded = mimeEncoder.encodeToString(testInputString.getBytes());
System.out.println("Java 8 Base64 MIME encoded: " + mimeEncoded);
byte[] mimeDecoded = mimeDecoder.decode(sunEncoded);
String mimeDecodedString = new String(mimeDecoded, Charset.forName("UTF-8"));
byte[] sunDecoded = unsupportedDecoder.decodeBuffer(mimeEncoded); // throws IOException
String sunDecodedString = new String(sunDecoded, Charset.forName("UTF-8"));
System.out.println(String.format("sun.misc decoded: %s | Java 8 Base64 decoded: %s", sunDecodedString, mimeDecodedString));
System.out.println("Decoded results are both equal: " + Objects.equals(sunDecodedString, mimeDecodedString));
System.out.println("Mime decoded result is equal to test input string: " + Objects.equals(testInputString, mimeDecodedString));
System.out.println("\n");
}
}
采纳答案by Stuart Marks
Here's a small test program that illustrates a difference in the encoded strings:
这是一个说明编码字符串差异的小测试程序:
byte[] bytes = new byte[57];
String enc1 = new sun.misc.BASE64Encoder().encode(bytes);
String enc2 = new String(java.util.Base64.getMimeEncoder().encode(bytes),
StandardCharsets.UTF_8);
System.out.println("enc1 = <" + enc1 + ">");
System.out.println("enc2 = <" + enc2 + ">");
System.out.println(enc1.equals(enc2));
Its output is:
它的输出是:
enc1 = <AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
>
enc2 = <AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA>
false
Note that the encoded output of sun.misc.BASE64Encoder
has a newline at the end. It doesn't alwaysappend a newline, but it happens to do so if the encoded string has exactly 76 characters on its last line. (The author of java.util.Base64
considered this to be a small bug in the sun.misc.BASE64Encoder
implementation – see the review thread).
请注意,编码输出sun.misc.BASE64Encoder
的末尾有一个换行符。它并不总是附加换行符,但如果编码字符串的最后一行正好有 76 个字符,它就会这样做。(作者java.util.Base64
认为这是实现中的一个小错误sun.misc.BASE64Encoder
- 请参阅评论线程)。
This might seem like a triviality, but if you had a program that relied on this specific behavior, switching encoders might result in malformed output. Therefore, I conclude that java.util.Base64
is nota drop-in replacement for sun.misc.BASE64Encoder
.
这可能看起来微不足道,但如果您的程序依赖于这种特定行为,则切换编码器可能会导致输出格式错误。因此,我断定java.util.Base64
是不是下降的替代产品sun.misc.BASE64Encoder
。
Of course, the intentof java.util.Base64
is that it's a functionally equivalent, RFC-conformant, high-performance, fully supported and specified replacement that's intended to support migration of code away from sun.misc.BASE64Encoder
. You need to be aware of some edge cases like this when migrating, though.
当然,意图的java.util.Base64
是,它是一个功能上等同,RFC-符合性,高性能,完全支持和指定的更换这是旨在支持代码迁移远离sun.misc.BASE64Encoder
。不过,您在迁移时需要注意一些像这样的边缘情况。
回答by jstedfast
There are no changes to the base64 specification between rfc1521 and rfc2045.
rfc1521 和 rfc2045 之间的 base64 规范没有变化。
All base64 implementations could be considered to be drop-in replacements of one another, the only differences between base64 implementations are:
所有 base64 实现都可以被认为是相互替换,base64 实现之间的唯一区别是:
- the alphabet used.
- the API's provided (e.g. some might take only act on a full input buffer, while others might be finite state machines allowing you to continue to push chunks of input through them until you are done).
- 使用的字母表。
- 提供的 API(例如,有些可能只对完整的输入缓冲区起作用,而其他可能是有限状态机,允许您继续通过它们推送输入块,直到完成)。
The MIME base64 alphabet has remained constant between RFC versions (it hasto or older software would break) and is: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
MIME base64 字母表在 RFC 版本之间保持不变(它必须或旧软件会损坏)并且是:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/
As Wikipedianotes, only the last 2 characters may change between base64 implementations.
正如维基百科所指出的,在 base64 实现之间,只有最后 2 个字符可能会发生变化。
As an example of a base64 implementation that doeschange the last 2 characters, the IMAP MUTF-7specification uses the following base64 alphabet: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,
作为确实更改最后 2 个字符的 base64 实现的示例,IMAP MUTF-7规范使用以下 base64 字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,
The reason for the change is that the /
character is often used as a path delimiter and since the MUTF-7 encoding is used to flatten non-ASCII directory paths into ASCII, the /
character needed to be avoided in encoded segments.
更改的原因是该/
字符通常用作路径分隔符,并且由于 MUTF-7 编码用于将非 ASCII 目录路径展平为 ASCII,因此/
需要在编码段中避免使用该字符。
回答by Simon G.
Assuming both encoders are bug free, then the RFC requires distinct encodings for every 0 byte, 1 byte, 2 byte and 3 bytes sequence. Longer sequences are broken down into as many 3 byte sequences as needed followed by a final sequence. Hence if the two implementations handle all 16,843,009 (1+256+65536+16777216) possible sequences correctly, then the two implementations are also identical.
假设两个编码器都没有错误,则 RFC 要求对每个 0 字节、1 字节、2 字节和 3 字节序列进行不同的编码。较长的序列根据需要被分解为多个 3 字节序列,然后是最终序列。因此,如果两个实现正确处理了所有 16,843,009 (1+256+65536+16777216) 个可能的序列,那么这两个实现也是相同的。
These tests only take a few minutes to run. By slightly changing your test code, I have done that and my Java 8 installation passed all the test. Hence the public implementation can be used to safely replace the sun.misc implementation.
这些测试只需几分钟即可运行。通过稍微更改您的测试代码,我已经做到了,我的 Java 8 安装通过了所有测试。因此,公共实现可用于安全地替换 sun.misc 实现。
Here is my test code:
这是我的测试代码:
import java.util.Base64;
import java.util.Arrays;
import java.io.IOException;
public class Base64EncodingDecodingRoundTripTest {
public static void main(String[] args) throws IOException {
System.out.println("Testing zero byte encoding");
encodeDecode(new byte[0]);
System.out.println("Testing single byte encodings");
byte[] test = new byte[1];
for(int i=0;i<256;i++) {
test[0] = (byte) i;
encodeDecode(test);
}
System.out.println("Testing double byte encodings");
test = new byte[2];
for(int i=0;i<65536;i++) {
test[0] = (byte) i;
test[1] = (byte) (i >>> 8);
encodeDecode(test);
}
System.out.println("Testing triple byte encodings");
test = new byte[3];
for(int i=0;i<16777216;i++) {
test[0] = (byte) i;
test[1] = (byte) (i >>> 8);
test[2] = (byte) (i >>> 16);
encodeDecode(test);
}
System.out.println("All tests passed");
}
static void encodeDecode(final byte[] testInput) throws IOException {
sun.misc.BASE64Encoder unsupportedEncoder = new sun.misc.BASE64Encoder();
sun.misc.BASE64Decoder unsupportedDecoder = new sun.misc.BASE64Decoder();
Base64.Encoder mimeEncoder = java.util.Base64.getMimeEncoder();
Base64.Decoder mimeDecoder = java.util.Base64.getMimeDecoder();
String sunEncoded = unsupportedEncoder.encode(testInput);
String mimeEncoded = mimeEncoder.encodeToString(testInput);
// check encodings equal
if( ! sunEncoded.equals(mimeEncoded) ) {
throw new IOException("Input "+Arrays.toString(testInput)+" produced different encodings (sun=\""+sunEncoded+"\", mime=\""+mimeEncoded+"\")");
}
// Check cross decodes are equal. Note encoded forms are identical
byte[] mimeDecoded = mimeDecoder.decode(sunEncoded);
byte[] sunDecoded = unsupportedDecoder.decodeBuffer(mimeEncoded); // throws IOException
if(! Arrays.equals(mimeDecoded,sunDecoded) ) {
throw new IOException("Input "+Arrays.toString(testInput)+" was encoded as \""+sunEncoded+"\", but decoded as sun="+Arrays.toString(sunDecoded)+" and mime="+Arrays.toString(mimeDecoded));
}
}
}
回答by user369151
I had same issue, when i moved from sun to java.util.base64, but org.apache.commons.codec.binary.Base64 this solved my problem
我有同样的问题,当我从 sun 移动到 java.util.base64 时,但是 org.apache.commons.codec.binary.Base64 这解决了我的问题