чтение из двоичного файла Scala - PullRequest
2 голосов
/ 17 февраля 2012

как читать двоичный файл кусками в scala.

Это было то, что я пытался сделать

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

значение, которое напечатано, является огромным числом. Принимая во внимание, что это должно возвратить 1 как первый вывод

1 Ответ

10 голосов
/ 18 февраля 2012

Поскольку вы видите 16777216, где вы ожидаете получить 1, похоже, проблема в том, что порядковый номер файла отличается от ожидаемой JVM.(То есть Java всегда ожидает порядка байтов с прямым порядком байтов / сети , а ваш файл содержит числа с прямым порядком байтов.)

Это проблема хорошо известной гаммы решений.

  • Например, эта страница имеет класс, который оборачивает входной поток и устраняет проблему.

  • В качестве альтернативы эта страница имеет функции, которые будут читать из DataInputStream.

  • Этот ответ StackOverflow содержит различные фрагменты, которые просто преобразуют int, если это все, что вам нужно сделать.

  • Вот фрагмент кода Scala , который добавит методы для чтения порядковых чисел из файла.

Самый простой ответ на ваш вопрос о том, как это исправить, это простопоменяйте местами байты, когда вы их читаете.Вы можете сделать это, заменив строку, которая выглядит как

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())
  }
}

The "Файл 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
...