Scala快速文本文件读取并上传到内存

elm*_*elm 12 io scala file scalaz scalaz-stream

在Scala中,为了读取文本文件并将其上传到数组中,常见的方法是

scala.io.Source.fromFile("file.txt").getLines.toArray
Run Code Online (Sandbox Code Playgroud)

特别是对于非常大的文件,是否有更快的方法可能首先将字节块读入内存然后用新行字符拆分它们?(有关常用方法,请参阅Scala中的读取整个文件.)

非常感谢.

Mar*_*ing 21

性能问题与读取数据的方式无关.它已经被缓冲了.在您实际遍历这些行之前,没有任何事情发生:

// 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
Run Code Online (Sandbox Code Playgroud)

考虑到我的硬盘驱动器的读取速度为每秒500mb,200mb的最佳时间为400ms,这意味着除了不将迭代器转换为阵列之外,没有改进的余地.

根据您的应用程序,您可以考虑直接使用迭代器而不是Array.因为在内存中使用如此庞大的阵列肯定会成为性能问题.


编辑:从你的评论我假设,你想进一步转换数组(也许你将线条分成列,就像你说你正在读数字数组).在这种情况下,我建议在阅读时进行转换.例如:

source.getLines.map(_.split(",").map(_.trim.toInt)).toArray
Run Code Online (Sandbox Code Playgroud)

比...快得多

source.getLines.toArray.map(_.split(",").map(_.trim.toInt))
Run Code Online (Sandbox Code Playgroud)

(对我来说它是1.9s而不是2.5s),因为你不是将整个巨型数组转换成另一个,而是将每一行单独转换为一个单独的数组(仅使用一半的堆空间).此外,由于读取文件是一个瓶颈,因此在读取时进行转换的好处是可以提高CPU利用率.