Byte数组到String并返回..问题-127

在下面的:

scala> (new String(Array[Byte](1, 2, 3, -1, -2, -127))).getBytes res12: Array[Byte] = Array(1, 2, 3, -1, -2, 63) 

为什么-127转换为63? 以及如何将其恢复为-127

[编辑:]下面的Java版本(以显示它不仅仅是“Scala问题”)

 c:\tmp>type Main.java public class Main { public static void main(String [] args) { byte [] b = {1, 2, 3, -1, -2, -127}; byte [] c = new String(b).getBytes(); for (int i = 0; i javac Main.java c:\tmp>java Main b:1; c:1 b:2; c:2 b:3; c:3 b:-1; c:-1 b:-2; c:-2 b:-127; c:63 

您正在调用的构造函数使得二进制到字符串转换使用解码不明显: String(byte[] bytes, Charset charset) 。 你想要的是根本不使用解码。

幸运的是,有一个构造函数: String(char[] value)

现在你有一个字符串中的数据,但你想要它完全按原样返回。 但猜猜怎么了! getBytes(Charset charset)这是正确的,还有一个自动应用的编码。 幸运的是,有一个toCharArray()方法。

如果必须以字节开头并以字节结束,则必须将char数组映射到字节:

 (new String(Array[Byte](1,2,3,-1,-2,-127).map(_.toChar))).toCharArray.map(_.toByte) 

因此,总结一下: StringArray[Byte]之间的转换Array[Byte]涉及编码和解码。 如果要将二进制数据放入字符串中,则必须在字符级别执行此操作。 但请注意,这将为您提供一个垃圾字符串(即结果将不是格式良好的UTF-16,因为String应该是这样),因此您最好将其作为字符读出并将其转换回字节。

可以将字节向上移动,例如,添加512; 然后你会得到一堆有效的单个Char码点。 但这是使用16位来表示每8个,50%的编码效率。 Base64是串行化二进制数据的更好选择(8位代表6,75%的效率)。

字符串用于存储文本而非二进制数据。

在您的默认字符编码中,-127没有字符,因此它将其替换为“?” 或63。

编辑:Base64是最好的选择,更好的是不使用文本来存储二进制数据。 它可以完成,但不能使用任何标准字符编码。 即你必须自己做编码。

要按字面意思回答您的问题,您可以使用自己的字符编码。 这是一个非常糟糕的主意,因为任何文本都可能以您看到的相同方式进行编码和修改。 使用Base64可以通过使用任何编码都安全的字符来避免这种情况。

 byte[] bytes = new byte[256]; for (int i = 0; i < bytes.length; i++) bytes[i] = (byte) i; String text = new String(bytes, 0); byte[] bytes2 = new byte[text.length()]; for (int i = 0; i < bytes2.length; i++) bytes2[i] = (byte) text.charAt(i); int count = 0; for (int i = 0; i < bytes2.length; i++) if (bytes2[i] != (byte) i) System.out.println(i); else count++; System.out.println(count + " bytes matched."); 

StringOps有一个方法getBytes ,我想这可能是将String转换为Array [Byte]的实际需要

http://www.scala-lang.org/api/2.10.2/index.html#scala.collection.immutable.StringOps

使用正确的字符集:

 scala> (new String(Array[Byte](1, 2, 3, -1, -2, -127), "utf-16")).getBytes("utf-16") res13: Array[Byte] = Array(-2, -1, 1, 2, 3, -1, -2, -127)