Scala Snippets - Read/Write to a file

1 minute read

Reading/Writing to a file - Scala I/O

Scala doesnโ€™t provide any native class/library support when it comes to writing output to a file or reading a file. So we borrow java I/O class in scala, create a new instance of PrintWriter and pass a new File object to it:

import java.io._        // to write to the file

//create a new file
val writer = new PrintWriter(new File("demo1.txt"))

//call the method write() on the object we created 
writer.write("This is a demo")

//close it
writer.close()

concise way of writing a file in scala

import java.io.PrintWriter
new PrintWriter("filename") { write("file contents"); close }

while this is a one liner, it is unsafe. The approach looks nice, it is neither exception-safe nor encoding-safe. If an exception happens in write(), close will never be called, and the file wonโ€™t be closed.

PrintWriter also uses the default system encoding, which is very bad for portability. And finally, this approach generates a separate class specifically for this line. Scala already generates tons of classes even for a simple code.

Consuming a file in scala

//Read a file
//to read a file, call the fromFile() method of class Source, with the filename as argument
import scala.io.Source  // to read a file
Source.fromFile("demo1.txt").mkString   // reads into a single line
scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)

The above leaves the file open, however. To avoid problems, you should close it like this:

val source = scala.io.Source.fromFile("file.txt")
val lines = try source.mkString finally source.close()

Another problem with the code above is that it is horrible slow due to its implementation nature. For larger files one should use:

source.getLines mkString "\n"

Refrain from reading an entire file into a single String. The getLines method returns a value of type Iterator[String]. Itโ€™s effectively a lazy cursor into the file, allowing you to examine just the data you need without risking memory glut.

//to read individual lines instead of the whole file at once, use the getLines() method
Source.fromFile("demo1.txt").getLines.foreach{x=>println(x)}

//iterator can also be used to get one line at a time
val it = Source.fromFile("demo1.txt").getLines()
it.next()
it.next()

//method take(n) to return the first n values from the iterator
it.take(2)

//print all the lines using while loop
while(it.hasNext){ print(it.next()) }

//method slice(start,until) returns an iterator over lines start to until-1.
it.slice(1,5)