title: Iterating over the lines of a file
body: <p>I'd like to write a simple function that iterates over the lines of a text file. I believe in <code>2.8</code> one could do:</p>
  
  <pre><code>def lines(filename: String) : Iterator[String] = { 
      scala.io.Source.fromFile(filename).getLines
  }
  </code></pre>
  
  <p>and that was that, but in <code>2.9</code> the above doesn't work and instead I must do:</p>
  
  <pre><code>def lines(filename: String) : Iterator[String] = { 
      scala.io.Source.fromFile(new File(filename)).getLines()
  }
  </code></pre>
  
  <p>Now, the trouble is, I want to compose the above iterators in a <code>for</code> comprehension:</p>
  
  <pre><code>for ( l1 &lt;- lines("file1.txt"); l2 &lt;- lines("file2.txt") ){ 
      do_stuff(l1, l2) 
  }
  </code></pre>
  
  <p>This again, used to work fine with <code>2.8</code> but causes a "too many open files" 
  exception to get thrown in <code>2.9</code>. This is understandable -- the second <code>lines</code> 
  in the comprehension ends up opening (and not closing) a file for each line 
  in the first.</p>
  
  <p>In my case, I know that the <code>"file1.txt"</code> is big and I don't want to suck it into<br>
  memory, but the second file is small, so I can write a different <code>linesEager</code> 
  like so:</p>
  
  <pre><code>def linesEager(filename: String): Iterator[String] = 
      val buf = scala.io.Source.fromFile(new File(filename))
      val zs  = buf.getLines().toList.toIterator
      buf.close()
      zs
  </code></pre>
  
  <p>and then turn my for-comprehension into:</p>
  
  <pre><code>for (l1 &lt;- lines("file1.txt"); l2 &lt;- linesEager("file2.txt")){ 
      do_stuff(l1, l2) 
  }
  </code></pre>
  
  <p>This works, but is clearly ugly. Can someone suggest a uniform &amp; clean 
  way of achieving the above. Seems like you need a way for the iterator
  returned by <code>lines</code> to <code>close</code> the file when it reaches the end, and 
  this must have been happening in <code>2.8</code> which is why it worked there? </p>
  
  <p>Thanks!</p>
  
  <p>BTW -- here is a minimal version of the full program that shows the issue:</p>
  
  <pre><code>import java.io.PrintWriter
  import java.io.File
  
  object Fail { 
  
    def lines(filename: String) : Iterator[String] = { 
      val f = new File(filename)
      scala.io.Source.fromFile(f).getLines()
    }
  
    def main(args: Array[String]) = { 
      val smallFile = args(0)
      val bigFile   = args(1)
  
      println("helloworld")
  
      for ( w1 &lt;- lines(bigFile)
          ; w2 &lt;- lines(smallFile)
          ) 
      {
        if (w2 == w1){
          val msg = "%s=%s\n".format(w1, w2)
          println("found" + msg)
        }
      }
  
      println("goodbye")
    }
  
  }
  </code></pre>
  
  <p>On <code>2.9.0</code> I compile with <code>scalac WordsFail.scala</code> and then I get this:</p>
  
  <pre><code>rjhala@goto:$ scalac WordsFail.scala 
  rjhala@goto:$ scala Fail passwd words
  helloworld
  java.io.FileNotFoundException: passwd (Too many open files)
      at java.io.FileInputStream.open(Native Method)
      at java.io.FileInputStream.&lt;init&gt;(FileInputStream.java:120)
      at scala.io.Source$.fromFile(Source.scala:91)
      at scala.io.Source$.fromFile(Source.scala:76)
      at Fail$.lines(WordsFail.scala:8)
      at Fail$$anonfun$main$1.apply(WordsFail.scala:18)
      at Fail$$anonfun$main$1.apply(WordsFail.scala:17)
      at scala.collection.Iterator$class.foreach(Iterator.scala:652)
      at scala.io.BufferedSource$BufferedLineIterator.foreach(BufferedSource.scala:30)
      at Fail$.main(WordsFail.scala:17)
      at Fail.main(WordsFail.scala)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:78)
      at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:24)
      at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:88)
      at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:78)
      at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
      at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
      at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:40)
      at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:56)
      at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)
      at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:89)
      at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
  </code></pre>