I/O Operations in Scala
Learn console input, formatted output, and file reading and writing in Scala with Source, Using, and Try for safe resource handling - with Docker-ready examples
Input and output is where Scala’s dual heritage is most visible. As a JVM language, Scala has the entire java.io and java.nio machinery available—every PrintWriter and FileWriter trick you know from Java works unchanged. But Scala layers its own idioms on top: scala.io.Source turns a file into an iterator of characters or lines so the collection methods you already know (mkString, getLines, zipWithIndex) work on files too, and string interpolators make formatted output both concise and type-checked.
The functional side of Scala shows up in how errors and resources are handled. Instead of scattering try/catch blocks, idiomatic Scala wraps a fallible read in Try, turning an exception into an ordinary value you can pattern match on—a Success carrying the result or a Failure carrying the error. And instead of hand-written finally blocks to close files, scala.util.Using guarantees a resource is released no matter how the block exits.
In this tutorial you’ll go beyond the println you met in Hello World: formatted output with the s and f interpolators, reading from standard input with scala.io.StdIn, and writing, appending to, and reading files—including how to handle a file that doesn’t exist without crashing.
Formatted Output
Scala offers three levels of output formatting. Plain print and println handle simple cases. The s interpolator embeds any expression inside a string with $name or ${expr}. The f interpolator adds printf-style format specifiers—and because it’s checked at compile time, passing a String to a %d slot is a compile error, not a runtime surprise. Classic printf is also available for those who want the Java-style API directly.
Create a file named FormattedOutput.scala:
| |
The f interpolator is worth adopting as your default for numeric formatting: it reads like an interpolated string but carries the full power of java.util.Formatter specifiers (%.2f, %8d, %x, and so on), with the compiler verifying that each expression’s type matches its specifier.
Reading from Standard Input
Console input goes through scala.io.StdIn, which wraps standard input in simple line-oriented methods. readLine() returns the next line without its trailing newline—one small convenience over Java’s raw streams. Converting text to a number is just a method call on the string: "42".toInt. Note that toInt throws on malformed input; in a program that must survive bad input you would wrap the conversion in Try, exactly as the file example below does for a missing file.
Create a file named ReadInput.scala:
| |
Everything here is an expression: each readLine() result flows straight into an immutable val, gets trimmed and parsed in one chain, and the sum is computed inline inside the interpolated string. There’s no mutable accumulator in sight—a small example of how Scala’s functional style shapes even mundane console code.
File I/O with Source, Using, and Try
For files, idiomatic Scala reads through scala.io.Source and writes through the Java classes it inherits from the JVM (PrintWriter, FileWriter). The interesting part is resource safety: Using.resource takes anything closeable, runs your function on it, and guarantees close() is called even if the body throws—Scala’s answer to Java’s try-with-resources. And when an operation might fail, Try converts the exception into a value you can pattern match on.
Create a file named FileIo.scala:
| |
Because Source is an Iterator[Char], reading a file feels like working with any Scala collection: mkString slurps it whole, getLines() yields an iterator of lines, and zipWithIndex numbers them—no manual loop counters. The final match on Try is the functional alternative to try/catch: the failure case is handled in the same pattern-matching style used everywhere else in Scala, and the program continues instead of crashing.
Running with Docker
You can run all three examples with the Scala CLI image—no local Scala installation required.
| |
The stdin example needs Docker’s -i flag so the piped input reaches the program; without it, readLine() sees an immediate end-of-file.
Expected Output
Running FormattedOutput.scala (the stderr line appears interleaved in a terminal):
Loading...done
Scala first appeared in 2004
pi to 2 places: 3.14
padded: 42
hex: ff, octal: 10
this goes to standard error
Running ReadInput.scala with the piped input Ada, 2, 40:
What is your name?
Hello, Ada! Enter two numbers, one per line.
Their sum is 42
Running FileIo.scala:
--- journal.txt (71 characters) ---
1: day 1: learned println
2: day 2: learned val and var
3: day 3: learned Using
could not read missing.txt: missing.txt (No such file or directory)
Key Concepts
- Two toolboxes, one language — Scala programs use
java.ioclasses likePrintWriterdirectly while layering Scala-native APIs (Source,StdIn,Using) on top; you pick whichever fits. - The
finterpolator is a type-checked printf —f"$pi%.2f"gives you the full formatter mini-language, and a mismatched specifier is a compile-time error rather than a runtime exception. Console.errseparates diagnostics from output — write errors to stderr so your program’s real stdout can be piped cleanly to files or other programs.Sourceturns files into iterators —mkStringreads a whole file,getLines()streams it line by line, and collection methods likezipWithIndexwork on files exactly as they do on lists.Using.resourceguarantees cleanup — it closes the file, writer, or anyAutoCloseableeven when the body throws, replacing hand-writtenfinallyblocks.Tryturns exceptions into values — a fallible read becomes aSuccessorFailureyou pattern match on, letting recovery logic use the same style as the rest of your Scala code.readLine()strips the newline — unlike Java’s raw streams,scala.io.StdInhands you the line content directly; you typically stilltrimbefore parsing numbers.- Appending needs an explicit flag —
new PrintWriter("file")truncates; wrap anew FileWriter("file", true)to append instead.
Running Today
All examples can be run using Docker:
docker pull virtuslab/scala-cli:latest
Comments
Loading comments...
Leave a Comment