我正在尝试读取一个二进制文件(16 MB),其中我只有16位编码的整数。所以为此,我使用了1 MB的块,它给了我一个字节数组。为了我自己的需要,我将这个字节数组转换为一个短数组,并使用以下函数进行转换,但是使用缓冲区读取此文件并将其转换为短数组需要5秒钟,这是否比我的解决方案更快?
def convert(in: Array[Byte]): Array[Short] = in.grouped(2).map {
case Array(one) => (one << 8 | (0 toByte)).toShort
case Array(hi, lo) => (hi << 8 | lo).toShort
} .toArray
val startTime = System.nanoTime()
val file = new RandomAccessFile("foo","r")
val defaultBlockSize = 1 * 1024 * 1024
val byteBuffer = new Array[Byte](defaultBlockSize)
val chunkNums = (file.length / defaultBlockSize).toInt
for (i <- 1 to chunkNums) {
val seek = (i - 1) * defaultBlockSize
file.seek(seek)
file.read(byteBuffer)
val s = convert(byteBuffer)
println(byteBuffer size)
}
val stopTime = System.nanoTime()
println("Perf of = " + ((stopTime - startTime) / 1000000000.0) + " for a duration of " + duration + " s")
答案 0 :(得分:2)
16 MB,除非您在功能手机或其他设备上运行,否则很容易适合内存。没有必要把它搞砸并使逻辑变得更难。
使用java.nio.files.Files.readAllBytes
:
val buffer = java.nio.files.Files.readAllBytes(myfile.toPath)
假设您没有使用Java 1.6。 (如果您坚持使用Java 1.6,请使用myfile.size
预先分配缓冲区大小,并在read
上使用FileInputStream
一次性完成所有操作。这并不困难,只是别忘了关闭它!)
然后,如果你不想自己转换,你可以
val bb = java.nio.ByteBuffer.wrap(buffer)
bb.order(java.nio.ByteOrder.nativeOrder)
val shorts = new Array[Short](buffer.length/2)
bb.asShortBuffer.get(shorts)
你已经完成了。
请注意,这是所有Java的东西;这里没有Scala特有的保存语法。
如果你想知道为什么这样比你的代码快得多,那是因为grouped(2)
将字节装箱并将它们放在一个数组中。对于你想要的每一个短片,这都是三个分配!您可以通过直接索引数组来自己完成,而且速度很快,但是为什么当ByteBuffer
和朋友完全按照您的需要做什么时,您会想要这样做?
如果您真的真的关心最后一个(奇数)字节,那么您可以使用(buffer.length + 1)/2
作为shorts
的大小,并使用{ {1}}获取最后一个字节。
答案 1 :(得分:0)
出现了一些问题:
如果byteBuffer
的大小始终为1024 * 1024,那么case Array(one)
中的convert
将永远不会被使用,因此不需要进行模式匹配。
此外,您可以避免使用尾递归函数的for循环。在val byteBuffer = ...
行之后,您可以用以下内容替换chunkNums和for循环:
@scala.annotation.tailrec
def readAndConvert(b: List[Array[Short]], file : RandomAccessFile) : List[Array[Short]] = {
if(file.read(byteBuffer) < 0)
b
else {
file.skipBytes(1024*1024)
readAndConvert(b.+:(convert(byteBuffer)), file)
}
}
val sValues = readAndConvert(List.empty[Array[Short]], file)
注意:因为列表预先加载比附加上面的循环快得多,所以从文件中的阅读顺序开始按相反的顺序获取转换后的值。