将 ByteArray 转换为 String 到 ByteArray

Vas*_*Vel 0 scala protocol-buffers playframework scalapb

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

人.proto:

syntax = "proto3";
  message Person{
    string name = 1;
    int32 age = 2;
  }
Run Code Online (Sandbox Code Playgroud)

sbt 编译后,它给出案例类 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
Run Code Online (Sandbox Code Playgroud)

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

Lev*_*sey 5

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

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

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

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

纯粹的 8 位编码,例如ISO-8859-1保证至少可以从字节数组中解码,但可能存在不可打印或控制字符,因此它不太有用:

val iso88591Representation = new String(newPerson.toByteArray, java.nio.charset.StandardCharsets.ISO_8859_1)
Run Code Online (Sandbox Code Playgroud)

或者,您可能需要像 Scala REPL(有时)如何呈现它的表示形式:

"Array(" + newPerson.toByteArray.mkString(", ") + ")"
Run Code Online (Sandbox Code Playgroud)