解码 Java 中的 Base64 字符串

Decoding Base64 String in Java

我正在使用 Java 并且我有一个 Base64 编码的字符串,我希望对其进行解码,然后进行一些操作来进行转换。

正确的解码值是在Java脚本中通过函数atob()获得的,但是在java中,使用Base64.decodeBase64()我无法获得相等的值。

示例:

对于:

String str = "AAAAAAAAAAAAAAAAAAAAAMaR+ySCU0Yzq+AV9pNCCOI="

使用 Java脚本 atob(str) 我得到 ->

"Æ‘û$‚SF3«àö“Bâ"

使用 Java new String(Base64.decodeBase64(str)) 我得到 ->

"Æ?û$?SF3«à§ö?â"


我可以解决此问题的另一种方法是 运行 Java 使用 Nashorn 引擎在 Java 中编写脚本,但我在 "$" 附近遇到错误符号。

当前代码:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
String script2 = "function decoMemo(memoStr){ print(atob(memoStr).split('')" + 
    ".map((aChar) => `0${aChar.charCodeAt(0).toString(16)}`" +
    ".slice(-2)).join('').toUpperCase());}";
try {
    engine.eval(script2);
    Invocable inv = (Invocable) engine;
    String returnValue = (String)inv.invokeFunction("decoMemo", memoTest );
    System.out.print("\n result: " + returnValue);
} catch (ScriptException | NoSuchMethodException e1) {
    e1.printStackTrace();

如有任何帮助,我们将不胜感激。我找了很多地方都找不到正确答案。

byte[] data = Base64.getDecoder().decode(str);

btoa 已损坏,不应使用。

问题是,字节不是字符。 Base64 编码只做一件事。它将 bytes 转换为几乎可以在任何 text-based 传输机制中存活的字符流。而 Base64 解码则相反,它将这些字符转换为 bytes.

令人困惑的是,您正在打印这些字节,就好像它们是字符一样。他们不是。

你最终得到完全相同的字节,但是 javascript 和 java 不同意你应该如何把它变成一个 ersatz 字符串,因为你试图将它打印到一个控制台。这是一个错误——字节不是字符。因此,正在使用某种字符集编码,而您不需要任何这些,因为这些字符显然不打算像那样打印。

Java 脚本排序 half-equates 字符和字节,并会自由地将一个转换为另一个,选择一些随机编码。钱币。 Java脚本在这方面很糟糕,它就是这样。 MDN docs on btoa 解释了为什么你不应该使用它。您 运行 遇到了 那个 问题。

不完全确定您如何在 java脚本中修复它 - 但也许您不需要它。 Java 对字节的解码非常好,javascript 也是如此,但是 javascript 然后将这些字节转换为一些愚蠢的字符,这就是问题所在。

你所拥有的根本不是文本字符串。赠品是开头的 AA。那些映射到许多零字节。这不会转换为任何标准字符集中有意义的文本。

所以你所拥有的很可能是二进制数据。将其转换为字符串不会为您提供有意义的文本。


现在解释一下您在 Java 和 Java 脚本之间看到的区别。在我看来,Java 和 Javascript 都在“尽最大努力”尝试转换二进制数据,就好像它是在 ISO-8859-1(又名 ISO LATIN-1)中编码的一样.

问题是一些字节代码映射到未分配的代码。

  • 在 Java 的情况下,那些未分配的代码被映射到 ?,无论是在创建字符串时还是在输出时。
  • 在 Java脚本情况下,未分配的代码未包含在字符串中,或​​者当您尝试显示它们时它们被删除了。

作为记录,这就是我上面的在线 base64 解码器的方式:

  ����������������Æû$SF3«àöBâ

未分配的代码是0x91 0x82和0x93。 0x15 和 0x0B 是 non-printing 控制代码。


但最重要的是,您不应在 Java 或 Java 脚本中将此数据转换为字符串。它应该被视为二进制;即字节值数组。