あるプログラマの日記

プログラマのメモ、出来事、考えたこと、勉強とかの雑記

java.nio.ByteBuffer

ByteBuffer は便利

DataInputStream の readFully みたいに指定サイズを
Byte バッファに読み込んで ByteBuffer にして返すメソッド。
この時のデータはリトルエンディアン

import java.nio.{ByteBuffer,ByteOrder}
..snip..
  def read[S <: { def read(b: Array[Byte], n: Int, len: Int): Int }](in: S)
    (size: Int): ByteBuffer = {
    val b = new Array[Byte](size)
    val bbuf = ByteBuffer.wrap(b)
    bbuf.order(ByteOrder.LITTLE_ENDIAN)
    var num = 0
    while (num < size) {
      val cnt = in.read(b, num, size - num)
      if (cnt < 0) throw new EOFException()
      num += cnt
    }
    bbuf
  }
..snip..

読みだしたデータを ByteBuffer にして扱うと
Int, Short, Double, 文字列 等の各種の型でデータを取り出して処理する際に便利。

..snip..
  val bbuf = read[InputStream](in)(32)

  println(" Int data : %d".format(bbuf.getInt(0)))
  val sdat: Int = bbuf.getShort(4)
  println(" Short data: %d".format(sdat))

  println(" Double data : %.10f".format(bbuf.getDouble(16)))
..snip..

ファイル保存した文字列を表示するときのエンコーディング指定

いまさらだがファイル保存した文字列のエンコーディング指定でハマった。
Shift_JIS でバイナリファイルに保存した文字列を読みだして
ローカルのエンコーディング(この時は EUC-JP)で表示する時のやり方

  def getStr(bb: ByteBuffer, pos: Int, size: Int): Pair[String,String] = {
    val enc = System.getProperty("file.encoding")
    val buf = new Array[Byte](size)
    for (i <- 0 until size) buf(i) = bb.get(pos + i)
    val hex = for (i <- 0 until size) yield { "%02X".format(buf(i)) }
    (hex.mkString, new String(new String(buf, "SJIS").getBytes(enc), enc))
  }

読みだしたデータを ByteBuffer で渡して表示エンコーディング文字列と
その文字列の16進数ダンプを返すメソッド。
データの ByteBuffer とその読み出し位置(pos)、読み出しサイズ(size)を
引数に指定して、読みだした文字列(表示エンコーディング)とその文字列
の16進数ダンプの文字列の Pair を返す。

..snip..
  val (hex, str) = getStr(bbuf, 32, 16)

  println(" str: %s".format(str))
  println(" hex: %s".format(hex)
..snip..