从二进制文件Scala中读取

Gau*_*rav 2 scala binary-data

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

这就是我想要做的

val fileInput = new FileInputStream("tokens")
    val dis = new DataInputStream(fileInput)
    var value = dis.readInt()
    var i=0;
println(value)
Run Code Online (Sandbox Code Playgroud)

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

Lei*_*and 10

因为你看到16777216你希望有一个1,所以听起来问题是文件的字节顺序与JVM期望的不同.(也就是说,Java总是期望大端/网络字节顺序,并且您的文件包含小端的数字.)

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

对于如何修复它的问题,最简单的答案就是在读取它们时简单地交换字节.你可以通过替换看起来像你的线来做到这一点

var value = dis.readInt()
Run Code Online (Sandbox Code Playgroud)

同

var value = java.lang.Integer.reverseBytes(dis.readInt())
Run Code Online (Sandbox Code Playgroud)

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

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())
  }
}
Run Code Online (Sandbox Code Playgroud)

上面提到的"endian.bin"文件包含一个大端序列1,后面是一个小端字节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
Run Code Online (Sandbox Code Playgroud)