为什么Java Base64在Eclipse和jar包中运行结果存在差异
问题根因
你遇到的差异本质是字符串转字节数组时未显式指定编码,依赖了环境的默认编码,具体原因如下:
- 代码中调用的
szFirst.getBytes()、coded.getBytes()都没有指定编码,会自动读取当前JVM运行环境的file.encoding默认值 - Eclipse运行时默认编码和终端执行
java -jar的默认编码不一致,其中145、130、135这几个字符值不属于UTF-8的有效单字节字符,编码不兼容时就会被替换为ASCII 63的问号(?)字符 - 你定义的char数组本身存储的是原始字节值,完全没必要经过String层中转再做Base64编解码,直接操作字节数组就能彻底规避编码问题
修复方案
方案1:直接操作字节数组(最优)
直接把原始数值存为byte数组,跳过String中转,完全规避编码影响:
import java.util.Arrays; import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder; public class TestB64 { public static void main(String[] args) { TestB64 b64 = new TestB64(); b64.doTheJob(); } public void doTheJob() { System.out.println("Java Version: " + System.getProperty("java.runtime.version")); // 改用byte数组存储原始值,超过127的数值强转为byte byte[] arr = { 54, 10, (byte)145, (byte)225, (byte)242, (byte)135, 6, (byte)130, 20, 113, 109, 35, 33 }; printByteArr(arr); Encoder enc = Base64.getEncoder(); String coded = enc.encodeToString(arr); Decoder dec = Base64.getDecoder(); byte[] arrSecond = dec.decode(coded); if (!Arrays.equals(arr, arrSecond)) System.err.println("Arrays are different !!!"); else System.out.println("Are equals !"); printByteArr(arrSecond); } private void printByteArr(byte[] arr) { for (byte b : arr) // 转为无符号int打印数值,避免负数显示 System.out.printf("%d,", Byte.toUnsignedInt(b)); System.out.println(); } }
方案2:显式指定统一编码
如果一定要用String中转,所有转字节、新建String的地方都显式指定统一编码:
import java.nio.charset.StandardCharsets; // 编码时显式指定UTF-8 String coded = enc.encodeToString(szFirst.getBytes(StandardCharsets.UTF_8)); // 解码时显式指定UTF-8 String szSecond = new String(dec.decode(coded.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
注意:这种方案下如果你的char数组中包含对应编码的非法字符,依然会出现字符替换问题,优先推荐方案1。
内容的提问来源于stack exchange,提问作者Claudio
相关产品推荐
相关产品推荐

