Scala - Итератор по всем строкам в файлах в каталоге

Мне очень нравится

for (line <- Source fromFile inputPath getLines) {doSomething line}

для итерации по файлу в scala, и мне интересно, есть ли способ использовать аналогичную конструкцию для итерации по строкам во всех файлах в каталоге.

Важным ограничением здесь является то, что все файлы суммируются до объема пространства, которое генерирует переполнение кучи. (думаю, десятки ГБ, поэтому увеличение размера кучи не является вариантом). Пока работаю, я катаюсь каждый раз в один файл и использую описанную выше конструкцию, которая работает b/c лени.

Точка, кажется, вызывает такие вопросы, как.. могу ли я объединить два (сто) ленивых итератора и получить действительно большой, действительно ленивый?

Ответы

Ответ 1

Да, хотя это не совсем так лаконично:

import java.io.File
import scala.io.Source

for {
  file <- new File(dir).listFiles.toIterator if file.isFile
  line <- Source fromFile file getLines
} { doSomething line }

Трюк flatMap и его синтаксический сахар for -понимание синтаксиса. Вышеупомянутое, например, более или менее эквивалентно следующему:

new File(dir)
  .listFiles.toIterator
  .filter(_.isFile)
  .flatMap(Source fromFile _ getLines)
  .map(doSomething)

Как отмечает Даниэль Собрал в комментарии ниже, этот подход (и код в вашем вопросе) оставит файлы открытыми. Если это одноразовый script, или вы просто работаете в REPL, это может быть не очень важно. Если вы столкнулись с проблемами, вы можете использовать рисунок pimp-my-library для реализации некоторого базового управления ресурсами:

implicit def toClosingSource(source: Source) = new {
  val lines = source.getLines
  var stillOpen = true
  def getLinesAndClose = new Iterator[String] {
    def hasNext = stillOpen && lines.hasNext
    def next = {
      val line = lines.next
      if (!lines.hasNext) { source.close() ; stillOpen = false }
      line
    }
  }
}

Теперь просто используйте Source fromFile file getLinesAndClose, и вам не придется беспокоиться о том, что файлы остаются открытыми.