【问题标题】:Issue with Base64 encoding/decoding: decoded string is '?'Base64 编码/解码问题:解码后的字符串是“?”
【发布时间】:2011-09-22 23:38:10
【问题描述】:

我正在尝试读取图像并使用 Base64 编码将其转换为字节数组,然后转换为字符串以通过网络发送。问题是当我尝试解码 Base64 编码的字符串时,我得到的数据不正确。

例如。我面临以下特殊字符的问题。

我正在使用以下代码进行编码:

byte[] b = Base64.encodeBase64(IOUtils.toByteArray(loInputStream));
String ab = new String(b);

IOUtilsorg.apache.commons.io.IOUtils

和loInput

解码代码:

byte[] c = Base64.decodeBase64(ab.getBytes());
String ca = new String(c);
System.out.println(ca);

它为解码的字符串打印?

谁能告诉我这个问题。

【问题讨论】:

  • Base64 类从何而来(这不是标准的 Java API 类)?
  • @jesper:我正在使用 apache commons (org.apache.commons.codec.binary.Base64)
  • nos 下面已经回答了您的问题。只是一个小评论:在将 String 转换为 byte[] 和反之亦然时,最好明确指定编码,而不是依赖于平台设置。我的意思是应该是 "new String(b, "UTF-8")" 和 "ab.getBytes("UTF-8")"
  • @Tarlog:啊啊啊!!非常感谢,这可能会解决我的问题。
  • @Tarlog:如果你使用encodeBase64String,你已经得到了一个 UTF-8 字符串(实际上是 US_ASCII,因为 Base64 只使用来自 US_ASCII 的字符)。

标签: java base64 java-io


【解决方案1】:

如果您的输入是图像,则将其编码为 base64 是有意义的 - base64 是文本,可以用字符串表示。

但再次解码,您将获得原始图像。图像通常是二进制格式;尝试将其转换为字符串是没有意义的 - 它不是文本。

即最后2行:

   String ca = new String(c);
   System.out.println(ca);

这样做毫无意义。

如果您想检查解码是否产生与原始输入相同的输出,请执行例如

  System.out.println("Original and decoded are the same: " + Arrays.equals(b,c));

(或将字节数组保存到文件并在图像查看器中查看图像)

【讨论】:

  • @nos:感谢您的回复,我将其转换回字符串的原因是因为我想使用 Base64 编码字符串再次重新创建该图像。有没有其他方法可以做同样的事情?
  • @nos:我正在将此编码字符串发送到我的应用程序,该应用程序使用我的 CMS api (alfresco) 创建图像,该图像将字符串作为图像数据的输入参数。
  • @Ankit 您已经在 byte[] c = Base64.decodeBase64(ab.getBytes()); 行中重新创建了它,数组 c 现在是原始图像。如果您的 alfresco api 将图像作为字符串,您需要阅读有关它期望的格式的文档。也许 API 希望您将图像的 base64 编码表示形式发送给它。 (即您将byte b[] = Base64.encodeBase64(IOUtils.toByteArray(loInputStream)); String ab = new String(b);的结果发送给它
  • @nos:你是对的,如果我尝试使用 FileOutputStream 将字节写入文件,它工作正常,但如果我将字节更改为字符串并尝试写入,则无法正常工作它。我将不得不考虑另一种方法来重新创建图像。感谢您的帮助
  • @Ankit 如前所述,您不应该将图像的字节直接转换为字符串。如果您需要图像中的字符串,请执行您已经执行的操作。你base64编码它。或者您将其编码为其他内容,例如base16(通常称为十六进制)
【解决方案2】:

正如我所说的elsewhere,在Java 中,String 用于文本,byte[] 用于二进制数据。

字符串≠字节[]

文本≠二进制数据

图像是二进制数据。 Base64 是一种允许通过与 US_ASCII 兼容的文本通道传输二进制数据的编码(ASCII 文本的超集也有类似的编码:Quoted Printable)。

所以,它是这样的:

Image (binary data) → Image (text, Base64 encoded binary data) → Image (binary data)

您将使用String encodeBase64String(byte[]) 进行编码,使用byte[] decode(String) 进行解码。这些是 Base64 唯一合理的 API,byte[] encodeBase64(byte[]) 具有误导性,结果是与 US_ASCII 兼容的文本(因此,String不是byte[])。

现在,文本有一个字符集和一个编码,String 在内部使用固定的 Unicode/UTF-16 字符集/编码组合,并且在将某些内容从/转换为 String 时,您必须指定一个字符集/编码,显式地或隐式地使用平台的默认编码(这是PrintStream.println() 所做的)。 Base64 文本是纯 US_ASCII,因此您需要使用它或 US_ASCII 的超集。 org.apache.commons.codec.binary.Base64 使用 UTF8,它是 US_ASCII 的超集,所以一切都很好。 (OTOH,内部 java.util.prefs.Base64 使用平台的默认编码,所以我猜如果你用 UTF-16 编码启动你的 JVM,它会中断)。

回到主题:您尝试将解码后的图像(二进制数据)打印为文本,这显然没有奏效。 PrintStream 具有可以写入二进制数据的 write() 方法,因此您可以使用它们,并且您会得到与编写原始图像相同的垃圾。最好使用FileOutputStream,并将生成的文件与原始图像文件进行比较。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-13
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 2011-10-31
    相关资源
    最近更新 更多