从二进制文件读取Scala

问题描述:

如何在scala中读取二进制文件块。从二进制文件读取Scala

这正是我试图做

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

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

+0

一定要具有文件在正确的endianess。 – ziggystar 2012-02-17 21:00:16

+0

究竟是哪一个数字呢?它碰巧是16777216?如果是这样,你有一个endian问题。 – 2012-02-17 21:02:27

+0

是的它的16777216 ..它搞乱了endian。它应该是1.我如何纠正它? – Gaurav 2012-02-17 21:03:16

因为你看到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作者决定应该是最终的,所以我们不能覆盖那些为小端文件提供透明阅读器的方法。

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 
+0

@Gaurav,它可能很明显,但你可以考虑扩展DataInputStream。 – 2012-02-18 02:23:02

+0

@EdStaub,你会认为Java扩展DataInputStream相当不方便,因为该类将readInt()等标记为final? – 2012-02-19 15:35:29

+0

哎呀 - 应该检查一下,我已经被烧得足以结束了。代表,那么,如果它是值得的。在这个例子中,很少使用DataInputStream方法,它可能是。 – 2012-02-19 16:21:53