2011-06-26 311 views
2

我正在尝试读取图像并使用Base64编码将其转换为字节数组,然后通过字符串通过网络发送。问题是,当我尝试解码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); 

它打印?用于解码的字符串。

任何人都可以让我知道这个问题。

+0

class'Base64'来自哪里(这不是标准的Java API类)? – Jesper

+0

@jesper:我正在使用apache commons(org.apache.commons.codec.binary.Base64) – Ankit

+0

下面的nos已经回答了你的问题。只是一个小小的评论:当将字符串转换为字节[]和反之亦然时,最好明确指定编码,而不要依赖平台设置。我的意思是它应该是“新字符串(b,”UTF-8“)”和“ab.getBytes(”UTF-8“)” – Tarlog

回答

1

正如我已经说过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,它会中断)。

返回主题:您已尝试将解码图像(二进制数据)作为文本打印出来,这显然不起作用。 PrintStreamwrite()方法可以写入二进制数据,所以你可以使用这些,你会得到相同的垃圾,就像你写了原始图像。使用FileOutputStream会更好,并将生成的文件与原始图像文件进行比较。

4

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

虽然解码它,但您会看到原始图像。图像通常是二进制格式;尝试将其转换为字符串没有任何意义 - 它不是文本。

也就是说,最后两行:

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

根本没有意义的事情。

如果你想检查解码是否产生与原始输入相同的输出,

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

(或字节数组保存到一个文件,并查看图像查看器中的图像)

+0

@nos:感谢您的回复,我之所以将它转换回字符串是因为我想再次使用Base64编码重新创建该图像串。有没有其他的方式来做同样的事情? – Ankit

+0

@nos:我将这个编码的字符串发送到我的应用程序,该应用程序使用我的CMS api(alfresco)创建图像,该图像将String作为图像数据的输入参数。 – Ankit

+2

@Ankit你已经在'byte [] c = Base64.decodeBase64(ab.getBytes())''这一行重新创建了它,''数组'c'现在是原始图像。如果你的露天api将图像作为一个字符串,你需要阅读关于它期望的格式的文档。也许API期望你发送图像的base64编码表示。 (即你发送它的结果'byte b [] = Base64.encodeBase64(IOUtils.toByteArray(loInputStream)); String ab = new String(b);' – nos