从二进制文件Scala中读取

时间:2012-02-17 19:59:41

标签: scala binary-data

如何在scala中以块的形式读取二进制文件。

这就是我想要做的事情

val fileInput = new FileInputStream("tokens")
    val dis = new DataInputStream(fileInput)
    var value = dis.readInt()
    var i=0;
println(value)

打印的值是一个巨大的数字。而它应该返回1作为第一个输出

1 个答案:

答案 0 :(得分:10)

因为你看到16777216你希望有一个1,所以听起来问题是文件的endianness与JVM期望的不同。 (即Java always expects big endian/network byte order,您的文件包含小端的数字。)

这是一个完善的解决方案的问题。

关于如何修复它的问题的最简单答案是在读取它们时简单地交换字节。你可以通过替换看起来像

的行来做到这一点
var value = dis.readInt()

var value = java.lang.Integer.reverseBytes(dis.readInt())

如果您想更简洁一点,可以使用隐式将 readXLE ()方法添加到DataInput的方法,或者可以覆盖DataInputStream以使 readXLE ()方法。不幸的是,Java作者认为 readX ()方法应该是最终的,所以我们不能覆盖这些方法来为小端文件提供透明的读取器。

object LittleEndianImplicits {
  implicit def dataInputToLittleEndianWrapper(d: DataInput) = new DataInputLittleEndianWrapper(d)

  class DataInputLittleEndianWrapper(d: DataInput) {
    def readLongLE(): Long = java.lang.Long.reverseBytes(d.readLong())
    def readIntLE(): Int = java.lang.Integer.reverseBytes(d.readInt())
    def readCharLE(): Char = java.lang.Character.reverseBytes(d.readChar())
    def readShortLE(): Short = java.lang.Short.reverseBytes(d.readShort())
  }
}

class LittleEndianDataInputStream(i: InputStream) extends DataInputStream(i) {
  def readLongLE(): Long = java.lang.Long.reverseBytes(super.readLong())
  def readIntLE(): Int = java.lang.Integer.reverseBytes(super.readInt())
  def readCharLE(): Char = java.lang.Character.reverseBytes(super.readChar())
  def readShortLE(): Short = java.lang.Short.reverseBytes(super.readShort())
}

object M {
  def main(a: Array[String]) {
    println("// Regular DIS")
    val d = new DataInputStream(new java.io.FileInputStream("endian.bin"))
    println("Int 1: " + d.readInt())
    println("Int 2: " + d.readInt())

    println("// Little Endian DIS")
    val e = new LittleEndianDataInputStream(new java.io.FileInputStream("endian.bin"))
    println("Int 1: " + e.readIntLE())
    println("Int 2: " + e.readIntLE())

    import LittleEndianImplicits._
    println("// Regular DIS with readIntLE implicit")
    val f = new DataInputStream(new java.io.FileInputStream("endian.bin"))
    println("Int 1: " + f.readIntLE())
    println("Int 2: " + f.readIntLE())
  }
}

上面提到的“endian.bin”文件包含一个大尾数1,后面是一个小尾数。运行上面的M.main()打印:

// Regular DIS
Int 1: 1
Int 2: 16777216
// LE DIS
Int 1: 16777216
Int 2: 1
// Regular DIS with readIntLE implicit
Int 1: 16777216
Int 2: 1