【问题标题】:Trimming byte array when converting byte array to string in Java/Scala在 Java/Scala 中将字节数组转换为字符串时修剪字节数组
【发布时间】:2014-06-01 02:43:09
【问题描述】:

使用 ByteBuffer,我可以将字符串转换为字节数组:

val x = ByteBuffer.allocate(10).put("Hello".getBytes()).array()
> Array[Byte] = Array(104, 101, 108, 108, 111, 0, 0, 0, 0, 0)

将字节数组转换为字符串时,我可以使用new String(x)。 但是,字符串变为hello?????,我需要在将其转换为字符串之前修剪字节数组。我怎样才能做到这一点?

我使用此代码来修剪零,但我想知道是否有更简单的方法。

def byteArrayToString(x: Array[Byte]) = {
    val loc = x.indexOf(0)
    if (-1 == loc)
      new String(x)
    else if (0 == loc)
      ""
    else
      new String(x.slice(0,loc))
}

【问题讨论】:

    标签: java string scala bytearray


    【解决方案1】:

    假设0: Byte是一个尾随值,那么

    implicit class RichToString(val x: java.nio.ByteBuffer) extends AnyVal {
      def byteArrayToString() = new String( x.array.takeWhile(_ != 0), "UTF-8" )
    }
    

    因此对于

    val x = ByteBuffer.allocate(10).put("Hello".getBytes())
    
    x.byteArrayToString
    res: String = Hello
    

    【讨论】:

      【解决方案2】:

      几个String constructors 接受一个偏移量+长度到byte[] - 这消除了事先创建一个新的修剪数组的需要。

      使用其中一个重载的构造函数可能如下所示:

      def byteArrayToString(x: Array[Byte]) = {
          val loc = x.indexOf(0)
          if (-1 == loc)
            new String(x)
          else if (0 == loc)
            ""
          else
            new String(x, 0, loc, "UTF-8") // or appropriate encoding
      }
      

      或者,保持 indexOf 的轻微变化:

      def byteArrayToString(arr: Array[Byte]) = {
          val loc = arr.indexOf(0)
          // length passed to constructor can be 0..arr.length
          new String(arr, 0, if (loc >= 0) loc else arr.length, "UTF-8")
      }
      

      或者,一行(感谢 find/Option):

      def byteArrayToString(arr: Array[Byte]) = {
          new String(arr, 0, arr.find(_ == 0) orElse arr.length, "UTF-8")
      }
      

      关于编码的想法:

      1. 通常建议使用显式编码,并且应使用getBytes 中指定的相同编码,如default may change。这是standard charset names

      2. 字节0可能出现在编码输出中之前数据的结尾,这取决于字符串输入(即NUL)和使用的编码。

      【讨论】:

        【解决方案3】:

        如果你只有一个String,我会使用.getBytes() -

        val x:Array[Byte] = "Hello".getBytes("UTF-8");
        

        输出是

        x: Array[Byte] = Array(72, 101, 108, 108, 111)
        

        对于不止一个String,我会使用ByteArrayOutputStream,就像这样-

        val baos = new java.io.ByteArrayOutputStream(10); //  <-- I might not use 10.
                                                          //  <-- Smells of premature opt.
        baos.write("Hello".getBytes("UTF-8"));
        baos.write(", World!".getBytes("UTF-8"));
        
        val x:Array[Byte] = baos.toByteArray(); // <-- x:Array[Byte], to specify the type.
        

        输出是

        x: Array[Byte] = Array(72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33)
        

        【讨论】:

          【解决方案4】:

          你可以这样做:

          val bb = java.nio.ByteBuffer.allocate(10).put("Hello".getBytes)
          val s = new String(bb.array, 0, bb.position)
          

          虽然这不会在 ByteBuffer 中表明您已阅读任何内容。正常模式是 flip 并使用 limit,但如果您只是抓取数组,您也可以在完成后使用 positionclear,然后再阅读更多内容。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-08-06
            • 2013-12-19
            • 2011-07-26
            • 1970-01-01
            相关资源
            最近更新 更多