从二进制文件读取Scala
如何在scala中读取二进制文件块。从二进制文件读取Scala
这正是我试图做
val fileInput = new FileInputStream("tokens")
val dis = new DataInputStream(fileInput)
var value = dis.readInt()
var i=0;
println(value)
其印刷是一个庞大的数字值。而它应该返回1作为第一个输出
因为你看到16777216你期望有一个1,这听起来像问题是该文件的endianness是不同于JVM所期望的。 (即,Java always expects big endian/network byte order和您的文件包含小端的数字。)
这是一个已经确立的色域解决方案的问题。
例如this page有一个包装输入流并使问题消失的类。
或者this page具有从DataInputStream读取的函数。
This StackOverflow answer有各种各样的片段,只需要转换一个int,如果这就是你需要做的。
Here's a Scala snippet这将添加方法从文件中读取小端数字。
对于如何解决这个问题,最简单的答案就是在读取它们时简单地交换字节。你可以做到这一点的更换你的线,看起来像
var value = dis.readInt()
与
var value = java.lang.Integer.reverseBytes(dis.readInt())
如果你想使这一点更简洁,你可以使用的隐含添加readXLE(无论是方法)方法到DataInput,或者您可以重写DataInputStream以使其具有readXLE()方法。不幸的是,Java作者决定应该是最终的,所以我们不能覆盖那些为小端文件提供透明阅读器的方法。
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海湾跟着小尾数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
@Gaurav,它可能很明显,但你可以考虑扩展DataInputStream。 – 2012-02-18 02:23:02
@EdStaub,你会认为Java扩展DataInputStream相当不方便,因为该类将readInt()等标记为final? – 2012-02-19 15:35:29
哎呀 - 应该检查一下,我已经被烧得足以结束了。代表,那么,如果它是值得的。在这个例子中,很少使用DataInputStream方法,它可能是。 – 2012-02-19 16:21:53
一定要具有文件在正确的endianess。 – ziggystar 2012-02-17 21:00:16
究竟是哪一个数字呢?它碰巧是16777216?如果是这样,你有一个endian问题。 – 2012-02-17 21:02:27
是的它的16777216 ..它搞乱了endian。它应该是1.我如何纠正它? – Gaurav 2012-02-17 21:03:16