0

我想将 ByteArray 转换为字符串,然后将字符串转换为 ByteArray,但是在转换值时发生了变化。有人帮助解决这个问题。

人.proto:

syntax = "proto3";
  message Person{
    string name = 1;
    int32 age = 2;
  }

在 sbt compile 之后,它给出了案例类 Person(由 google protobuf 在编译时创建)

我的主课:

val newPerson = Person(
      name = "John Cena",
      age = 44                        //output
    )
    println(newPerson.toByteArray)    //[B@50da041d
    val l = newPerson.toByteArray.toString  
    println(l)                        //[B@7709e969
    val l1 = l.getBytes
    println(l1)                      //[B@f44b405

为什么价值观改变了?如何正确转换??

4

1 回答 1

3

[B@...是 JVM 字节数组.toString返回的格式,只是[B(意思是“字节数组”)和一个十六进制字符串,类似于数组所在的内存地址(我故意不称它为指针,但它是类似;该十六进制字符串到内存地址的精确映射取决于 JVM,并且可能会受到正在使用的垃圾收集器等因素的影响)。重要的是,两个具有相同字节的不同数组将具有不同.toString的 s。请注意,在某些地方(例如 REPL),Scala 会打印类似的内容Array(-127, 0, 0, 1)而不是调用.toString: 这可能会导致混淆。

似乎toByteArray每次调用它都会发出一个新数组。所以第一次调用时newPerson.toByteArray,你会在对应的位置得到一个数组50da041d。第二次调用它时,您会在对应的位置获得一个具有相同内容的字节数组,7709e969并将字符串保存[B@7709e969到变量l中。然后,当您调用getBytes该字符串(将其保存在 中l1)时,您会得到一个字节数组,它是字符串“[B@7709e969”在对应位置的编码f44b405

所以在对应的位置50da041d7709e969你有两个不同的字节数组,它们恰好包含相同的元素(这些元素是 proto 表示中的字节newPerson)。在与您对应的位置f44b405有一个字节数组,其中字节编码(在某些字符集中,可能是 UTF-16?)[B@7709e969

因为 proto 并不是真正的字符串,所以没有通用的方法来获取有用的字符串(取决于您正在处理的有用的定义)。您可以尝试将字节数组解释toByteArray为具有给定字符编码的字符串,但不能保证任何给定的原型在任意字符编码中都是有效的。

一个纯 8 位的编码,比如ISO-8859-1保证至少可以从字节数组中解码,但可能有不可打印或控制字符,所以它不太可能有用:

val iso88591Representation = new String(newPerson.toByteArray, java.nio.charset.StandardCharsets.ISO_8859_1)

或者,您可能想要一个类似 Scala REPL 将如何(有时)呈现它的表示:

"Array(" + newPerson.toByteArray.mkString(", ") + ")"
于 2022-02-23T17:01:30.787 回答