Java字节数组转换为字符串再转换为字节数组

191

我正在尝试理解将byte[]转换成string、将byte[]的string表示形式转换为byte[]的过程... 我将byte[]转换成string进行发送,然后期望我的Web服务(使用Python编写)将数据直接传送回客户端。

当我从Java应用程序发送数据时...

Arrays.toString(data.toByteArray())

需要发送的字节数..

[B@405217f8

发送(这是Arrays.toString()的结果,应该是我的字节数据的字符串表示形式,这些数据将通过网络发送):

[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]

在Python端,Python服务器将一个字符串返回给调用者(我可以看到它与我发送到服务器的字符串相同)。

[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]

服务器应将此数据返回给客户端,在客户端可以进行验证。

客户端接收到的响应(作为字符串)如下所示

[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]

我似乎无法弄清如何将接收到的字符串转换为byte[]。

无论我尝试什么,最终得到的byte数组看起来都像这样...

[91, 45, 52, 55, 44, 32, 49, 44, 32, 49, 54, 44, 32, 56, 52, 44, 32, 50, 44, 32, 49, 48, 49, 44, 32, 49, 49, 48, 44, 32, 56, 51, 44, 32, 49, 49, 49, 44, 32, 49, 48, 57, 44, 32, 49, 48, 49, 44, 32, 51, 50, 44, 32, 55, 56, 44, 32, 55, 48, 44, 32, 54, 55, 44, 32, 51, 50, 44, 32, 54, 56, 44, 32, 57, 55, 44, 32, 49, 49, 54, 44, 32, 57, 55, 93]

或者我可以获得以下字节表示:

B@2a80d889

这两个与我发送的数据不同... 我确定我错过了些非常简单的东西...

有任何帮助吗?!


请注意,通常您会使用基于64位编码(0QEQVAJlblNvbWUgTkZDIERhdGE=)或十六进制编码(d101105402656e536f6d65204e46432044617461)的字节;而不是带有分隔符、瑕疵和其他东西的数组编码。因此,这个问题和答案对于99%的情况都不适用。请注意,TCP和HTTP完全能够使用“POST”处理更大量的二进制数据。 - Maarten Bodewes
12个回答

283

你不能只是拿返回的字符串并从中构造一个字符串…它不再是一个字节数组数据类型,它已经是一个字符串;你需要解析它。例如:

String response = "[-47, 1, 16, 84, 2, 101, 110, 83, 111, 109, 101, 32, 78, 70, 67, 32, 68, 97, 116, 97]";      // response from the Python script

String[] byteValues = response.substring(1, response.length() - 1).split(",");
byte[] bytes = new byte[byteValues.length];

for (int i=0, len=bytes.length; i<len; i++) {
   bytes[i] = Byte.parseByte(byteValues[i].trim());     
}

String str = new String(bytes);
**编辑**
在你的问题中,你说:“无论我尝试什么,最终得到的字节数组看起来都像这样... [91, 45, ...]”,因为91[的字节值,所以[91, 45, ...]是字符串"[-45, 1, 16, ..."的字节数组。
方法Arrays.toString()将返回指定数组的String表示形式;这意味着返回的值将不再是一个数组。例如:
byte[] b1 = new byte[] {97, 98, 99};

String s1 = Arrays.toString(b1);
String s2 = new String(b1);

System.out.println(s1);        // -> "[97, 98, 99]"
System.out.println(s2);        // -> "abc";

你可以看到,s1保存了数组b1的字符串表示形式,而s2保存了包含在b1中的字节的字符串表示形式。

现在,在你的问题中,你的服务器返回类似于s1的字符串,因此要恢复数组表示形式,你需要使用相反的构造方法。如果s2.getBytes()new String(b1)的相反操作,那么你需要找到Arrays.toString(b1)的相反操作,因此我在这个答案的第一个代码段中粘贴了代码。


2
太棒了!我认为你完全理解了我的意思...我不是来自Java背景,所以我无法真正弄清楚我需要的转换。只是为了信息,我正在将s1发送到服务器,服务器会用s1回复(我可以验证服务器已经接收并回复了s1中的数据),所以我确实需要你建议的Arrays.toString()的相反操作...而且你的解决方案非常好!干杯! - 0909EM
1
谢谢Yanick。但是对于每个图像,它会循环2046次,因为bytes.length的值为2046。有没有其他方法可以做到这一点? - Gugan
如果您接收到的数据确实是需要像我的答案中的变量response的值一样解析的人类可读字符串,那么很遗憾,没有其他方法。最好的方法是以原始数据(二进制)的形式接收字节,或者甚至作为Base64字符串接收,这只需要您将其转换回基于256(二进制)的值即可。 - Yanick Rochon
4
除了一个正确但不完整的答案之外,需要补充以下内容:1)在Java中将任何byte[]数组转换为String时,都应该指定字符集。byte[]数组是UTF-8还是其他类型?没有明确说明或者不知道它是什么可能会导致错误。2)Java使用Big-Endian编码,但例如微软系统使用Little-Endian。处理表示数字的byte[]数组时,源/目标系统的“字节序”会产生影响,但是当处理基于字符的字符串时,则没有问题。 - Darrell Teague

139
String coolString = "cool string";

byte[] byteArray = coolString.getBytes();

String reconstitutedString = new String(byteArray);

System.out.println(reconstitutedString);

这将输出“cool string”到控制台。 很容易理解。

6
许多踩,但却很少解释......我的话有问题吗?当我使用它时它是有效的,问题是如何在字节和字符串之间转换,是吗? - CorayThan
2
解决这个问题的答案实际上被标记为答案。从记忆中来看,它并不像你所建议的那么简单...请查看 Yanick 的答案,我认为你误解了我的问题,但感谢你的回复。 - 0909EM
10
实际上,这完全没有回答楼主的问题。如果你真正仔细阅读过,你会发现他接收到的 byte[]String 的形式表示;也就是说,是 "[97, 98, 99]" 而不是 [97, 98, 99]。这意味着你的答案甚至不适用于这种情况。 - arkon
2
你的答案是将String转换为byte[]再转换为String。我认为问题要求是将byte[]转换为String再转换为byte[] - Wundwin Born
15
可能并非对所问问题的正确回答,但它帮助我解决了问题。这就是为什么人们在贬低别人的回复之前应该多思考一下。谢谢CorayThan! - Roberto Santos
显示剩余4条评论

22

我的行动:

回复客户:

byte[] result = ****encrypted data****;

String str = Base64.encodeBase64String(result);

return str;

收到来自客户端的消息:

 byte[] bytes = Base64.decodeBase64(str);

您的数据将以此格式传输:

OpfyN9paAouZ2Pw+gDgGsDWzjIphmaZbUyFx5oRIN1kkQ1tDbgoi84dRfklf1OZVdpAV7TonlTDHBOr93EXIEBoY1vuQnKXaG+CJyIfrCWbEENJ0gOVBr9W3OlFcGsZW5Cf9uirSmx/JLLxTrejZzbgq3lpToYc3vkyPy5Y/oFWYljy/3OcC/S458uZFOc/FfDqWGtT9pTUdxLDOwQ6EMe0oJBlMXm8J2tGnRja4F/aVHfQddha2nUMi6zlvAm8i9KnsWmQG//ok25EHDbrFBP2Ia/6Bx/SGS4skk/0couKwcPVXtTq8qpNh/aYK1mclg7TBKHfF+DHppwd30VULpA== 

7
Arrays.toString() 的作用是创建一个字符串表示您的 byteArray 中每个单独字节的表示形式。
请查看 API 文档 Arrays API 要将响应字符串转换回原始字节数组,您必须使用 split(",") 或类似方法将其转换为集合,然后将其中每个单独项转换为一个字节以重新创建您的字节数组。

6

在Java中将字节数组转换为字符串,以及将字符串转换回字节数组非常简单。我们需要知道何时以正确的方式使用“new”关键字。可以按照以下步骤完成:

将字节数组转换为字符串:

byte[] bytes = initializeByteArray();
String str = new String(bytes);

将字符串转换为字节数组:

String str = "Hello"
byte[] bytes = str.getBytes();

更多详细信息,请参见:http://evverythingatonce.blogspot.in/2014/01/tech-talkbyte-array-and-string.html


2
不,你没有读懂问题,或者你可能没有理解这个问题。正如你所看到的,这个问题已经在几年前得到了回答... - 0909EM

3
你所看到的来自字节数组的输出([B@405217f8)也是长度为零的字节数组(即new byte [0])的输出。看起来这个字符串是对数组的引用,而不是我们从常规集合的toString()方法中期望的数组内容描述。
和其他回答者一样,我会向你介绍接受byte[]参数的String构造函数,以从字节数组的内容构建字符串。如果你想从TCP连接获得字节,应该能够从套接字的InputStream中读取原始字节。
如果你已经将这些字节作为String(使用InputStreamReader)读取,则可以使用getBytes()函数将字符串转换为字节。请确保向String构造函数和getBytes()函数传递所需的字符集,只有当InputStreamReader可以将字节数据转换为字符时,此方法才有效。
如果你想处理原始字节,你真的应该避免使用这个流读取器层。

2

[JDK8]

import java.util.Base64;

转换为字符串:

String str = Base64.getEncoder().encode(new byte[]{ -47, 1, 16, ... });

转换为字节数组:

byte[] bytes = Base64.getDecoder().decode("JVBERi0xLjQKMyAwIG9iago8P...");

2
你不能只发送字节作为字节,或将每个字节转换为字符并作为字符串发送吗?按照你的方法,当你只有11个字节要发送时,它将占用至少85个字符。你可以创建一个字节的字符串表示形式,这样它就会变成"[B@405217f8",在Python中可以轻松地将其转换为bytesbytearray对象。如果失败,你可以将它们表示为一系列十六进制数字("5b42403430353231376638"),占用22个字符,这可以很容易地在Python端使用binascii.unhexlify()进行解码。

1
[B@405217f8 是 Java 数组的对象 ID,而不是数组的内容。对象 ID 当然不能“轻松地在 Python 中转换为字节或字节数组对象”。在大小方面,你最好将 byte[] 转换为 base64 字符串。 - Boris B.
你说得对,我天真地假设0909EM知道如何区分对象的(已类型化)地址和对象的内容。 - JAB

1

如果你想将字符串转换回字节数组,则需要使用 String.getBytes()(或等效的 Python 函数),这将允许你打印出原始的字节数组。


0
使用以下代码 API 将字节码字符串转换为字节数组。
 byte[] byteArray = DatatypeConverter.parseBase64Binary("JVBERi0xLjQKMyAwIG9iago8P...");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接