How to close enumerated file?

215 views Asked by At

Say, in an action I have:

val linesEnu = {
    val is = new java.io.FileInputStream(path)
    val isr = new java.io.InputStreamReader(is, "UTF-8")
    val br = new java.io.BufferedReader(isr)
    import scala.collection.JavaConversions._
    val rows: scala.collection.Iterator[String] = br.lines.iterator
    Enumerator.enumerate(rows)
}

Ok.feed(linesEnu).as(HTML)

How to close readers/streams?

2

There are 2 answers

0
Michael Zajac On BEST ANSWER

There is a onDoneEnumerating callback that functions like finally (will always be called whether or not the Enumerator fails). You can close the streams there.

val linesEnu = {
    val is = new java.io.FileInputStream(path)
    val isr = new java.io.InputStreamReader(is, "UTF-8")
    val br = new java.io.BufferedReader(isr)
    import scala.collection.JavaConversions._
    val rows: scala.collection.Iterator[String] = br.lines.iterator
    Enumerator.enumerate(rows).onDoneEnumerating {
        is.close()
        // ... Anything else you want to execute when the Enumerator finishes.
    }
}
1
Travis Brown On

The IO tools provided by Enumerator give you this kind of resource management out of the box—e.g. if you create an enumerator with fromStream, the stream is guaranteed to get closed after running (even if you only read a single line, etc.).

So for example you could write the following:

import play.api.libs.iteratee._

val splitByNl = Enumeratee.grouped(
  Traversable.splitOnceAt[Array[Byte], Byte](_ != '\n'.toByte) &>>
  Iteratee.consume()
) compose Enumeratee.map(new String(_, "UTF-8"))

def fileLines(path: String): Enumerator[String] =
  Enumerator.fromStream(new java.io.FileInputStream(path)).through(splitByNl)

It's a shame that the library doesn't provide a linesFromStream out of the box, but I personally would still prefer to use fromStream with hand-rolled splitting, etc. over using an iterator and providing my own resource management.