在Scala中,读取文本文件并将其上传到数组中的常见方法是
scala.io.Source.fromFile("file.txt").getLines.toArray
特别是对于非常大的文件,也许有一种更快的方法,先将字节块读入内存,然后通过换行符进行分割?(有关常用方法,请参见在Scala中读取整个文件。)
非常感谢。
在Scala中,读取文本文件并将其上传到数组中的常见方法是
scala.io.Source.fromFile("file.txt").getLines.toArray
特别是对于非常大的文件,也许有一种更快的方法,先将字节块读入内存,然后通过换行符进行分割?(有关常用方法,请参见在Scala中读取整个文件。)
非常感谢。
性能问题与读数据的方式无关,数据已经被缓存。只有在实际迭代行时才会发生任何事情:
// measures time taken by enclosed code
def timed[A](block: => A) = {
val t0 = System.currentTimeMillis
val result = block
println("took " + (System.currentTimeMillis - t0) + "ms")
result
}
val source = timed(scala.io.Source.fromFile("test.txt")) // 200mb, 500 lines
// took 0ms
val lines = timed(source.getLines)
// took 0ms
timed(lines.next) // read first line
// took 1ms
// ... reset source ...
var x = 0
timed(lines.foreach(ln => x += ln.length)) // "use" every line
// took 421ms
// ... reset source ...
timed(lines.toArray)
// took 915ms
考虑我的硬盘的读取速度每秒为500mb,对于200mb的数据,最佳时间是400ms,这意味着除了不将迭代器转换为数组外,没有其他改进的余地。
根据你的应用程序,你可以考虑直接使用迭代器而不是数组。因为在内存中处理如此巨大的数组肯定会成为性能问题。
编辑:从你的评论中我猜测你想进一步转换该数组(例如将行分割成列,正如你所说你正在读取一个数字数组)。在这种情况下,我建议在读取时进行转换。例如:
source.getLines.map(_.split(",").map(_.trim.toInt)).toArray
比...快很多。
source.getLines.toArray.map(_.split(",").map(_.trim.toInt))
对我来说,它只需要1.9秒而不是2.5秒,因为你并没有将整个巨大的数组转换成另一个数组,而是仅仅单独地处理每一行,最终得到一个单一的数组(使用了一半的堆空间)。此外,由于读取文件是一个瓶颈,边读取边转换的好处是可以更好地利用CPU。
Source
使用BufferedSource
,而BufferedSource
又使用了 Java 的BufferedReader
。因此,它已经将数据块读入内存 - 而不是逐字节读取。 - DNAfromFile()
有一个重载形式,它接受一个缓冲区大小参数。你尝试增加过这个参数吗?建议大于2048。 - n0741337