Skip to content

Scala Files I/O

File input/output (I/O) in Scala often involves using Java’s java.io classes, but wrapped with Scala features for better resource management and integration. The scala.io.Source object provides convenient ways to read files, and libraries like os-lib offer more Scala-idiomatic APIs, though Java interop is perfectly viable.

Using java.io.PrintWriter and java.io.FileWriter is common. It’s crucial to manage resources correctly, ensuring files are closed even if errors occur. scala.util.Using (Scala 2.13+) is the recommended way.

import java.io.{File, PrintWriter, FileWriter}
import scala.util.{Try, Using}
@main def WriteFileDemo(): Unit = {
val fileName = "output.txt"
val content = "Hello from Scala!\nThis is line 2."
val result: Try[Unit] = Using(new PrintWriter(new FileWriter(new File(fileName)))) { writer =>
writer.println(content) // println adds a newline
writer.write("This uses write.")
println(s"Successfully wrote to $fileName")
}
result.recover { // Handle potential errors during file writing/closing
case e: Exception => println(s"Error writing to file $fileName: ${e.getMessage}")
}
}

This code attempts to write to output.txt. Using ensures the PrintWriter (and underlying FileWriter) is closed automatically. The Try wrapper allows handling potential IOExceptions gracefully.

To read input from the console (standard input), use scala.io.StdIn.

import scala.io.StdIn
@main def ReadInputDemo(): Unit = {
print("Please enter your name: ")
val name = StdIn.readLine()
print("Please enter your age: ")
val age = StdIn.readInt() // Or readLine() and convert with .toIntOption
println(s"\nThanks, $name! You are $age years old.")
}

Run this, and it will prompt you for input:

$ scala ReadInputDemo
Please enter your name: Scala User
Please enter your age: 5
Thanks, Scala User! You are 5 years old.

StdIn offers various methods like readLine(), readInt(), readDouble(), etc.

scala.io.Source provides convenient ways to read file content. Again, proper resource management is essential.

import scala.io.Source
import scala.util.Using
import java.nio.charset.StandardCharsets // Specify encoding
@main def ReadFileLinesDemo(): Unit = {
val fileName = "output.txt" // Use the file created earlier
println(s"Reading content from $fileName:")
val linesResult: Try[List[String]] = Using(Source.fromFile(fileName, StandardCharsets.UTF_8.name())) { source =>
source.getLines().toList // Read all lines into a List
}
linesResult match {
case scala.util.Success(lines) =>
lines.zipWithIndex.foreach { case (line, index) =>
println(f"${index + 1}%2d: $line")
}
case scala.util.Failure(ex) =>
println(s"Error reading file: ${ex.getMessage}")
}
}

Output (based on the previous writing example):

Reading content from output.txt:
1: Hello from Scala!
2: This is line 2.
3: This uses write.
import scala.io.Source
import scala.util.Using
@main def ReadFileStringDemo(): Unit = {
val fileName = "output.txt"
val contentResult: Try[String] = Using(Source.fromFile(fileName)) { source =>
source.mkString // Read the entire file into a single String
}
contentResult match {
case scala.util.Success(content) =>
println(s"\n-- File content as single string --\n$content")
case scala.util.Failure(ex) =>
println(s"Error reading file: ${ex.getMessage}")
}
}
  • Resource Management: Always ensure files/streams are closed. scala.util.Using is the best practice.
  • Error Handling: File operations can fail. Use Try or Either to handle potential IOExceptions gracefully.
  • Character Encoding: Be mindful of character encoding (e.g., UTF-8). Specify it when reading/writing if it differs from the platform default.
  • Libraries: For more complex file system operations (listing directories, copying, deleting, watching files), consider libraries like os-lib by Li Haoyi, which offer a more Scala-like API than raw Java interop.