如何在scala中讀取二進制文件塊。從二進制文件讀取Scala
這正是我試圖做
val fileInput = new FileInputStream("tokens")
val dis = new DataInputStream(fileInput)
var value = dis.readInt()
var i=0;
println(value)
其印刷是一個龐大的數字值。而它應該返回1作爲第一個輸出
如何在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