Why do I get a java.nio.BufferUnderflowException in this Scala - scala

I was trying to do some scripting in Scala, to process some log files:
scala> import io.Source
import io.Source
scala> import java.io.File
import java.io.File
scala> val f = new File(".")
f: java.io.File = .
scala> for (l <- f.listFiles) {
| val src = Source.fromFile(l).getLines
| println( (0 /: src) { (i, line) => i + 1 } )
| }
3658
java.nio.BufferUnderflowException
at java.nio.Buffer.nextGetIndex(Unknown Source)
at java.nio.HeapCharBuffer.get(Unknown Source)
at scala.io.BufferedSource$$anon$2.next(BufferedSource.scala:86)
at scala.io.BufferedSource$$anon$2.next(BufferedSource.scala:74)
at scala.io.Source$$anon$6.next(Source.scala:307)
at scala.io.Source$$anon$6.next(Source.scala:301)
at scala.Iterator$cla...
Why do I get this java.nio.BufferUnderflowException?
NOTE - I'm processing 10 log files, each about 1MB in size

I got BufferUnderflowException exception when I opened a file with the wrong enconding. It contained illegal characters (according to the wrong encoding) and this misleading exception was thrown.

I'd also be interested as to exactly why this is happening but I'd guess it's to do with the fact that Source is an object (i.e. a singleton) and how it is gets transparently reset. You can fix the problem as follows:
for (l <- g.listFiles if !l.isDirectory) {
| val src = Source.fromFile(l)
| println( (0 /: src.getLines) { (i, line) => i + 1 } )
| src.reset
| }
The important bit is the reset - which should probably be in a try-finally block (although the isDirectory test is probably useful too)

This is essentially a restatement of Elazar's answer, but you will also get this exception if you try to read a binary file using scala.io.Source.fromFile.
I just ran into this (accidentally trying to read a .jpg with fromFile) due to a very stupid bug in something I wrote...

Related

Wait for a "Process" in Scala to complete

So there is this function in my program, that downloads a quite heavy zip file (about 500 megabytes) and then extracts the file and removes the zip file itself.
And obviously I want to wait for the file to download completely, then wait to unzip it completely and then remove the zip file itself (I just need the Json files inside). This is the code that I use currently:
import java.io.File
import java.net.URL
import scala.sys.process._
/* other functions */
// downloading, unzipping and removing are in separate functinos, but I
// aggregated them all here for simplicity
def downloadZipThenExtract(link: String, filePath: String): Future[Int] = {
val urlObject = new URL(link)
val file = new File(filePath)
Future {
val download: ProcessBuilder = urlObject #> file
val unzip: ProcessBuilder = s"unzip ${file.getPath} -d ${file.getParent}"
val delete: ProcessBuilder = s"rm ${file.getPath}"
/*
I've already tried this:
(download ### unzip ### delete) !
And every other solution, none of them worked
*/ // =>
download !
Thread.sleep(900000) // wait 15 minutes to download
unzip !
Thread.sleep(60000) // One minute to unzip
delete !
}
}
And as you can see, I found no other approach than freezing the thread to complete the download and unzipping, which of course sucks. So I wanted to know if you guys know any better approach, thanks.
I am not sure why you think that "freezing the thread" sucks. If you have to wait for the process to finish, then you have to wait for it.
But if it is just Thread.sleep that you see as problematic, then I have good news for you: you don't need it :)
download !
unzip !
delete !
I know you said you already tried "every other solution, and nothing worked", but if you have indeed tried this one, you gotta elaborate, because then I don't know what you mean when you say it "doesn't work".
I almost forgot about this question of mine, which I'd like to answer it in case anybody else faces this problem, since someone just upvoted the question.
My solution was to use akka, then put three streams inside my code, where obviously, first one downloads the data and puts it in the desired zip file, the second one extracts the zip file using java nio, and the last one just deletes the zip file.
Note that there's some extra code which you might not need, like the println's in case of exceptions and other stuff, I just wanted to share the idea and the solution.
here is my code:
def downloadFilesInto(fullPath: String, link: String)(implicit materializer: Materializer): Future[Int] = {
val directory: File = new File(fullPath).getParentFile
val urlObj = new URL(link)
val fileOutputStream = new FileOutputStream(fullPath)
val readableChannel = Channels.newChannel(urlObj.openStream())
val source = Source.single(1)
val downloaderFlow: Flow[Int, Long, NotUsed] = Flow[Int].map { _ =>
val size: Long = fileOutputStream.getChannel.transferFrom(readableChannel, 0, Long.MaxValue)
fileOutputStream.close()
readableChannel.close()
size
}
val unzipFlow: Flow[Long, Int, NotUsed] = Flow[Long].map { size =>
println(s"file downloaded, properties:\n type: zip\n size: ${size.toString.take(3)} MB")
val zipFile = new ZipFile(new File(fullPath))
val entries = zipFile.entries().asScala.toList
val eachFileExtractionResult: List[Int] =
entries.map { entry =>
try {
val path = new File(directory + "/" + entry.getName).toPath
Files.copy(zipFile.getInputStream(entry), path)
0
} catch {
case ex: Exception =>
println(
s"""
| Caught an Exception while unzipping file: ${entry.getName}
| Type: ${ex.getClass}
| Cause: ${ex.getCause}
| Message: ${ex.getMessage}
|""".stripMargin
)
1
case th: Throwable =>
println(
s"""
| Caught a throwable while unzipping file: ${entry.getName}
| Type: ${th.getClass}
| Cause: ${th.getCause}
| Message: ${th.getMessage}
|""".stripMargin
)
2
}
}
val unsuccessfulTries = eachFileExtractionResult.filterNot(_ == 0)
if (unsuccessfulTries.isEmpty)
0
else unsuccessfulTries.head
}
val removeFlow: Flow[Int, Int, NotUsed] = Flow[Int].map {
case 0 => // successfully unzipped
s"rm $fullPath".!
case whatever => whatever
}
val sink = Sink.fold[Int, Int](0)(_ + _)
source.viaMat(downloaderFlow)(Keep.right)
.viaMat(unzipFlow)(Keep.right)
.viaMat(removeFlow)(Keep.right)
.toMat(sink)(Keep.right)
.run()
}

Akka streams: Reading multiple files

I have a list of files. I want:
To read from all of them as a single Source.
Files should be read sequentially, in-order. (no round-robin)
At no point should any file be required to be entirely in memory.
An error reading from a file should collapse the stream.
It felt like this should work: (Scala, akka-streams v2.4.7)
val sources = Seq("file1", "file2").map(new File(_)).map(f => FileIO.fromPath(f.toPath)
.via(Framing.delimiter(ByteString(System.lineSeparator), 10000, allowTruncation = true))
.map(bs => bs.utf8String)
)
val source = sources.reduce( (a, b) => Source.combine(a, b)(MergePreferred(_)) )
source.map(_ => 1).runWith(Sink.reduce[Int](_ + _)) // counting lines
But that results in a compile error since FileIO has a materialized value associated with it, and Source.combine doesn't support that.
Mapping the materialized value away makes me wonder how file-read errors get handled, but does compile:
val sources = Seq("file1", "file2").map(new File(_)).map(f => FileIO.fromPath(f.toPath)
.via(Framing.delimiter(ByteString(System.lineSeparator), 10000, allowTruncation = true))
.map(bs => bs.utf8String)
.mapMaterializedValue(f => NotUsed.getInstance())
)
val source = sources.reduce( (a, b) => Source.combine(a, b)(MergePreferred(_)) )
source.map(_ => 1).runWith(Sink.reduce[Int](_ + _)) // counting lines
But throws an IllegalArgumentException at runtime:
java.lang.IllegalArgumentException: requirement failed: The inlets [] and outlets [MergePreferred.out] must correspond to the inlets [MergePreferred.preferred] and outlets [MergePreferred.out]
The code below is not as terse as it could be, in order to clearly modularize the different concerns.
// Given a stream of bytestrings delimited by the system line separator we can get lines represented as Strings
val lines = Framing.delimiter(ByteString(System.lineSeparator), 10000, allowTruncation = true).map(bs => bs.utf8String)
// given as stream of Paths we read those files and count the number of lines
val lineCounter = Flow[Path].flatMapConcat(path => FileIO.fromPath(path).via(lines)).fold(0l)((count, line) => count + 1).toMat(Sink.head)(Keep.right)
// Here's our test data source (replace paths with real paths)
val testFiles = Source(List("somePathToFile1", "somePathToFile2").map(new File(_).toPath))
// Runs the line counter over the test files, returns a Future, which contains the number of lines, which we then print out to the console when it completes
testFiles runWith lineCounter foreach println
Update Oh, I didn't see the accepted answer because I didn't refresh the page >_<. I'll leave this here anyway since I've also added some notes about error handling.
I believe the following program does what you want:
import akka.NotUsed
import akka.actor.ActorSystem
import akka.stream.{ActorMaterializer, IOResult}
import akka.stream.scaladsl.{FileIO, Flow, Framing, Keep, Sink, Source}
import akka.util.ByteString
import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success}
import scala.util.control.NonFatal
import java.nio.file.Paths
import scala.concurrent.duration._
object TestMain extends App {
implicit val actorSystem = ActorSystem("test")
implicit val materializer = ActorMaterializer()
implicit def ec = actorSystem.dispatcher
val sources = Vector("build.sbt", ".gitignore")
.map(Paths.get(_))
.map(p =>
FileIO.fromPath(p)
.viaMat(Framing.delimiter(ByteString(System.lineSeparator()), Int.MaxValue, allowTruncation = true))(Keep.left)
.mapMaterializedValue { f =>
f.onComplete {
case Success(r) if r.wasSuccessful => println(s"Read ${r.count} bytes from $p")
case Success(r) => println(s"Something went wrong when reading $p: ${r.getError}")
case Failure(NonFatal(e)) => println(s"Something went wrong when reading $p: $e")
}
NotUsed
}
)
val finalSource = Source(sources).flatMapConcat(identity)
val result = finalSource.map(_ => 1).runWith(Sink.reduce[Int](_ + _))
result.onComplete {
case Success(n) => println(s"Read $n lines total")
case Failure(e) => println(s"Reading failed: $e")
}
Await.ready(result, 10.seconds)
actorSystem.terminate()
}
The key here is the flatMapConcat() method: it transforms each element of a stream into a source and returns a stream of elements yielded by these sources if they are run sequentially.
As for handling errors, you can either add a handler to the future in the mapMaterializedValue argument, or you can handle the final error of the running stream by putting a handler on the Sink.foreach materialized future value. I did both in the example above, and if you test it, say, on a nonexisting file, you'll see that the same error message will be printed twice. Unfortunately, flatMapConcat() does not collect materialized values, and frankly I can't see the way it could do it sanely, therefore you have to handle them separately, if necessary.
I do have one answer out of the gate - don't use akka.FileIO. This appears to work fine, for example:
val sources = Seq("sample.txt", "sample2.txt").map(io.Source.fromFile(_).getLines()).reduce(_ ++ _)
val source = Source.fromIterator[String](() => sources)
val lineCount = source.map(_ => 1).runWith(Sink.reduce[Int](_ + _))
I'd still like to know whether there's a better solution.

How do I provide basic configuration for a Scala application?

I am working on a small GUI application written in Scala. There are a few settings that the user will set in the GUI and I want them to persist between program executions. Basically I want a scala.collections.mutable.Map that automatically persists to a file when modified.
This seems like it must be a common problem, but I have been unable to find a lightweight solution. How is this problem typically solved?
I do a lot of this, and I use .properties files (it's idiomatic in Java-land). I keep my config pretty straight-forward by design, though. If you have nested config constructs you might want a different format like YAML (if humans are the main authors) or JSON or XML (if machines are the authors).
Here's some example code for loading props, manipulating as Scala Map, then saving as .properties again:
import java.io._
import java.util._
import scala.collection.JavaConverters._
val f = new File("test.properties")
// test.properties:
// foo=bar
// baz=123
val props = new Properties
// Note: in real code make sure all these streams are
// closed carefully in try/finally
val fis = new InputStreamReader(new FileInputStream(f), "UTF-8")
props.load(fis)
fis.close()
println(props) // {baz=123, foo=bar}
val map = props.asScala // Get to Scala Map via JavaConverters
map("foo") = "42"
map("quux") = "newvalue"
println(map) // Map(baz -> 123, quux -> newvalue, foo -> 42)
println(props) // {baz=123, quux=newvalue, foo=42}
val fos = new OutputStreamWriter(new FileOutputStream(f), "UTF-8")
props.store(fos, "")
fos.close()
Here's an example of using XML and a case class for reading a config. A real class can be nicer than a map. (You could also do what sbt and at least one project do, take the config as Scala source and compile it in; saving it is less automatic. Or as a repl script. I haven't googled, but someone must have done that.)
Here's the simpler code.
This version uses a case class:
case class PluginDescription(name: String, classname: String) {
def toXML: Node = {
<plugin>
<name>{name}</name>
<classname>{classname}</classname>
</plugin>
}
}
object PluginDescription {
def fromXML(xml: Node): PluginDescription = {
// extract one field
def getField(field: String): Option[String] = {
val text = (xml \\ field).text.trim
if (text == "") None else Some(text)
}
def extracted = {
val name = "name"
val claas = "classname"
val vs = Map(name -> getField(name), claas -> getField(claas))
if (vs.values exists (_.isEmpty)) fail()
else PluginDescription(name = vs(name).get, classname = vs(claas).get)
}
def fail() = throw new RuntimeException("Bad plugin descriptor.")
// check the top-level tag
xml match {
case <plugin>{_*}</plugin> => extracted
case _ => fail()
}
}
}
This code reflectively calls the apply of a case class. The use case is that fields missing from config can be supplied by default args. No type conversions here. E.g., case class Config(foo: String = "bar").
// isn't it easier to write a quick loop to reflect the field names?
import scala.reflect.runtime.{currentMirror => cm, universe => ru}
import ru._
def fromXML(xml: Node): Option[PluginDescription] = {
def extract[A]()(implicit tt: TypeTag[A]): Option[A] = {
// extract one field
def getField(field: String): Option[String] = {
val text = (xml \\ field).text.trim
if (text == "") None else Some(text)
}
val apply = ru.newTermName("apply")
val module = ru.typeOf[A].typeSymbol.companionSymbol.asModule
val ts = module.moduleClass.typeSignature
val m = (ts member apply).asMethod
val im = cm reflect (cm reflectModule module).instance
val mm = im reflectMethod m
def getDefault(i: Int): Option[Any] = {
val n = ru.newTermName("apply$default$" + (i+1))
val m = ts member n
if (m == NoSymbol) None
else Some((im reflectMethod m.asMethod)())
}
def extractArgs(pss: List[List[Symbol]]): List[Option[Any]] =
pss.flatten.zipWithIndex map (p => getField(p._1.name.encoded) orElse getDefault(p._2))
val args = extractArgs(m.paramss)
if (args exists (!_.isDefined)) None
else Some(mm(args.flatten: _*).asInstanceOf[A])
}
// check the top-level tag
xml match {
case <plugin>{_*}</plugin> => extract[PluginDescription]()
case _ => None
}
}
XML has loadFile and save, it's too bad there seems to be no one-liner for Properties.
$ scala
Welcome to Scala version 2.10.0-RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_06).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import reflect.io._
import reflect.io._
scala> import java.util._
import java.util._
scala> import java.io.{StringReader, File=>JFile}
import java.io.{StringReader, File=>JFile}
scala> import scala.collection.JavaConverters._
import scala.collection.JavaConverters._
scala> val p = new Properties
p: java.util.Properties = {}
scala> p load new StringReader(
| (new File(new JFile("t.properties"))).slurp)
scala> p.asScala
res2: scala.collection.mutable.Map[String,String] = Map(foo -> bar)
As it all boils down to serializing a map / object to a file, your choices are:
classic serialization to Bytecode
serialization to XML
serialization to JSON (easy using Jackson, or Lift-JSON)
use of a properties file (ugly, no utf-8 support)
serialization to a proprietary format (ugly, why reinvent the wheel)
I suggest to convert Map to Properties and vice versa. "*.properties" files are standard for storing configuration in Java world, why not use it for Scala?
The common way are *. properties, *.xml, since scala supports xml natively, so it would be easier using xml config then in java.

Why do I get a MalformedInputException from this code?

I'm a newbie in Scala, and I wanted to write some sourcecodes from myself for me to get better.
I've written a simple object (with a main entry) in order to simulate a "grep" call on all files of the current directory. (I launch the program from Eclipse Indigo, and in Debian Squeeze) :
package com.gmail.bernabe.laurent.scala.tests
import java.io.File
import scala.io.Source
object DealWithFiles {
def main(args:Array[String]){
for (result <- grepFilesHere(".*aur.*"))
println(result)
}
private def grepFilesHere(pattern:String):Array[String] = {
val filesHere = new File(".").listFiles
def linesOfFile(file:File) =
Source.fromFile(file).getLines.toList
for (file <- filesHere;
if file.isFile
)
yield linesOfFile(file)(0)
}
}
But I get a java.nio.charset.MalformedInputException, which I am not able to solve :
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:260)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:319)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at scala.io.BufferedSource$BufferedLineIterator.hasNext(BufferedSource.scala:67)
at scala.collection.Iterator$class.foreach(Iterator.scala:772)
at scala.io.BufferedSource$BufferedLineIterator.foreach(BufferedSource.scala:43)
at scala.collection.generic.Growable$class.$plus$plus$eq(Growable.scala:48)
at scala.collection.mutable.ListBuffer.$plus$plus$eq(ListBuffer.scala:130)
at scala.collection.TraversableOnce$class.toList(TraversableOnce.scala:242)
at scala.io.BufferedSource$BufferedLineIterator.toList(BufferedSource.scala:43)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles$.linesOfFile$1(DealWithFiles.scala:18)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles$$anonfun$grepFilesHere$2.apply(DealWithFiles.scala:23)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles$$anonfun$grepFilesHere$2.apply(DealWithFiles.scala:20)
at scala.collection.TraversableLike$WithFilter$$anonfun$map$2.apply(TraversableLike.scala:697)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:34)
at scala.collection.mutable.ArrayOps.foreach(ArrayOps.scala:38)
at scala.collection.TraversableLike$WithFilter.map(TraversableLike.scala:696)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles$.grepFilesHere(DealWithFiles.scala:20)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles$.main(DealWithFiles.scala:10)
at com.gmail.bernabe.laurent.scala.tests.DealWithFiles.main(DealWithFiles.scala)
Thanks in advance for helps :)
From the JavaDoc:
MalformedInputException
thrown when an input byte sequence is not legal for given charset, or
an input character sequence is not a legal sixteen-bit Unicode
sequence.
Pass the currect encoding as parameter to Source.fromFile method.
You can handle this character encoding exception by adding below snippet in your code
import scala.io.Codec
import java.nio.charset.CodingErrorAction
implicit val codec = Codec("UTF-8")
codec.onMalformedInput(CodingErrorAction.REPLACE)
codec.onUnmappableCharacter(CodingErrorAction.REPLACE)

Iterating over the lines of a file

I'd like to write a simple function that iterates over the lines of a text file. I believe in 2.8 one could do:
def lines(filename: String) : Iterator[String] = {
scala.io.Source.fromFile(filename).getLines
}
and that was that, but in 2.9 the above doesn't work and instead I must do:
def lines(filename: String) : Iterator[String] = {
scala.io.Source.fromFile(new File(filename)).getLines()
}
Now, the trouble is, I want to compose the above iterators in a for comprehension:
for ( l1 <- lines("file1.txt"); l2 <- lines("file2.txt") ){
do_stuff(l1, l2)
}
This again, used to work fine with 2.8 but causes a "too many open files"
exception to get thrown in 2.9. This is understandable -- the second lines
in the comprehension ends up opening (and not closing) a file for each line
in the first.
In my case, I know that the "file1.txt" is big and I don't want to suck it into
memory, but the second file is small, so I can write a different linesEager
like so:
def linesEager(filename: String): Iterator[String] =
val buf = scala.io.Source.fromFile(new File(filename))
val zs = buf.getLines().toList.toIterator
buf.close()
zs
and then turn my for-comprehension into:
for (l1 <- lines("file1.txt"); l2 <- linesEager("file2.txt")){
do_stuff(l1, l2)
}
This works, but is clearly ugly. Can someone suggest a uniform & clean
way of achieving the above. Seems like you need a way for the iterator
returned by lines to close the file when it reaches the end, and
this must have been happening in 2.8 which is why it worked there?
Thanks!
BTW -- here is a minimal version of the full program that shows the issue:
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 <- lines(bigFile)
; w2 <- lines(smallFile)
)
{
if (w2 == w1){
val msg = "%s=%s\n".format(w1, w2)
println("found" + msg)
}
}
println("goodbye")
}
}
On 2.9.0 I compile with scalac WordsFail.scala and then I get this:
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.<init>(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)
scala-arm provides a great mechanism for automagically closing resources when you're done with them.
import resource._
import scala.io.Source
for (file1 <- managed(Source.fromFile("file1.txt"));
l1 <- file1.getLines();
file2 <- managed(Source.fromFile("file2.txt"));
l2 <- file2.getLines()) {
do_stuff(l1, l2)
}
But unless you're counting on the contents of file2.txt to change while you're looping through file1.txt, it would be best to read that into a List before you loop. There's no need to convert it into an Iterator.
Maybe you should take a look at scala-arm (https://github.com/jsuereth/scala-arm) and let the closing of the files (file input streams) happen automatically in the background.