字节数组转字符串及其反向操作...关于-127的问题

33
在下面的内容中:
 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 < 6; i++){
            System.out.println("b:"+b[i]+"; c:"+c[i]);
        }
    }
}
c:\tmp>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
4个回答

55
构造函数的调用使得将二进制转换为字符串的过程不够明显: String(byte[] bytes, Charset charset)。你需要使用根本没有解码的方式。
幸运的是,有一个适用于这种情况的构造函数:String(char[] value)
现在,你已经将数据保存在了字符串中,但是你想要保持和原来一样。但是注意!getBytes(Charset charset) 也会自动应用编码。不过,幸运的是,有一个方法可以将其转换为字符数组:toCharArray()
如果你必须从字节开始并以字节结束,则需要将字符数组映射到字节:
(new String(Array[Byte](1,2,3,-1,-2,-127).map(_.toChar))).toCharArray.map(_.toByte)

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

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


12

字符串是用来存储文本而不是二进制数据。

在默认字符编码中,没有-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.");

1
所以我猜转换为base64是我的唯一选择。 - Jus12

9

你能解释一下这个跟 Java 的 getBytes 有什么不同,以及为什么它会起作用吗?链接中似乎没有任何解释。 - Jus12

5

使用正确的字符集:

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)

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