【问题标题】:Byte array to String and back.. issues with -127字节数组到字符串并返回.. -127 的问题
【发布时间】:2016-09-13 15:33:09
【问题描述】:

如下:

 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

【问题讨论】:

    标签: java scala


    【解决方案1】:

    您调用的构造函数使得二进制到字符串的转换使用解码并不明显: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] 之间的转换涉及编码和解码。如果要将二进制数据放入字符串中,则必须在字符级别进行。但是请注意,这会给您一个垃圾字符串(即,结果将不是格式正确的 UTF-16,正如 String 所期望的那样),因此您最好将其作为字符读出并转换它回到字节。

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 所以我想转换为 base64 是我唯一的选择。
      【解决方案3】:

      StringOps 有一个方法getBytes,我认为这可能是人们真正想要将 String 转换为 Array[Byte]

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

      【讨论】:

      • 您能解释一下这与 Java 的 getBytes 有何不同,以及为什么会这样吗?链接上似乎没有任何解释。
      【解决方案4】:

      使用正确的字符集:

      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)
      

      【讨论】:

        猜你喜欢
        • 2012-02-24
        • 2015-05-24
        • 2014-07-30
        • 2013-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多