Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to close stream associated w/ iterator returned by Source.fromFile("/tmp/foo").getLines()

I need to create an iterator using Source.getLines(), and from a quick look at the Scala source code, and after running some tests it seems like the iterator does not close even after the iterator is exhausted (i.e., after hasNext() begins to be false).

I'm wondering what is Scala's recommended technique for closing/releasing resources used to create an iterator. I found an interesting library that seems like it would do the trick:

https://github.com/jsuereth/scala-arm

However, I'd prefer to use core scala libraries instead of pulling in 3rd party stuff if possible. If you are interested in how I tested this (on Linux using the 'lsof' to list open files), my code is below:

        object Test extends App {
          import sys.process._
          import scala.io.Source._


          "echo hello world" #> new java.io.File("/tmp/testing") !

          val  src = fromFile("/tmp/testing")
          val iter: Iterator[String] = src.getLines()
          while (iter.hasNext) {
            println("line=" + iter.next())
          }

          println("iterator exhausted.. sleeping while we check if file is still open using lsof")
          Thread.sleep(200000)
        }

After running the program and it is still sleeping, run this command:

 lsof   | grep /tmp/testing

and you will probably see output like this:

java  15813 ...253,0.... 12 .. lots-of-othernumbers..0462 /tmp/testing

Then when the program terminates, the grep will come up empty (as you would think).

Thanks in advance for any tips you can provide !

like image 254
Chris Bedford Avatar asked Sep 16 '15 03:09

Chris Bedford


1 Answers

This is the pattern I tend to use:

def using[R <: Closeable, T](stream: R)(f: R => T): T =
  try {
    f(stream)
  } finally {
    stream.close()
  }

Which you can use like so:

def readSomeLines(is: InputStream) = {
  using(new BufferedReader(new InputStreamReader(is))) { stream =>
    Iterator.continually(stream.readLine().takeWhile(_ != null)).foreach(println)
  }
}

readSomeLines(new FileInputStream("/tmp/foo"))
like image 139
jhn Avatar answered Sep 27 '22 18:09

jhn