I/O Operations in Kotlin
Read from the console, write and read files, format output, and handle I/O errors in Kotlin with Docker-ready examples
Input and output are how a program talks to the outside world—printing results, reading what a user types, and moving data in and out of files. You already met println() in Hello World; this tutorial goes deeper into console I/O, formatted output, and file handling.
Because Kotlin runs on the JVM, it has full access to Java’s mature java.io and java.nio libraries. But Kotlin layers a set of concise, idiomatic extension functions on top of them. Where Java might need a BufferedReader, a try/finally, and several lines of ceremony, Kotlin often gets the job done in one expression like File("data.txt").readText().
Kotlin’s multi-paradigm nature shows up clearly in I/O. You can write imperative loops that read line by line, or functional pipelines that stream lines through map and filter. The use function brings automatic resource management (like Java’s try-with-resources) in a clean, functional style. In this tutorial you’ll write a program that prints formatted output and reads and writes files, then handle input and I/O errors safely.
Console Output and Formatting
print() writes without a trailing newline; println() adds one. For anything beyond simple concatenation, Kotlin borrows Java’s printf-style format specifiers through the String.format extension, called simply as "...".format(...).
Create a file named IoOperations.kt:
| |
Here writeText creates (or overwrites) the file, appendText adds to it, readText pulls the entire contents into a String, and readLines returns a List<String>—one entry per line. These extension functions handle opening and closing the file for you.
Reading Console Input
readLine() reads a single line from standard input and returns a String?—nullable, because input can reach end-of-file. Kotlin’s null-safety features make you handle that case explicitly.
Create a file named EchoInput.kt:
| |
isNullOrBlank() is a standard-library extension that safely checks for null, empty, or whitespace-only input in one call. To convert typed input to a number, chain toIntOrNull(), which returns null instead of throwing on bad input.
Buffered I/O with Automatic Cleanup
For larger files you want buffering and guaranteed resource cleanup. The use function runs a block and closes the resource afterward—even if an exception is thrown—mirroring Java’s try-with-resources. useLines streams a file lazily, so you never hold the whole thing in memory.
Create a file named BufferedIo.kt:
| |
Handling I/O Errors
File operations can fail: a file may be missing, unreadable, or locked. Reading a nonexistent file throws a FileNotFoundException. Wrap risky calls in a try/catch and respond gracefully instead of crashing.
Create a file named SafeRead.kt:
| |
Because missing.txt does not exist, readText() throws, the catch block runs, and the program reports the problem cleanly rather than terminating with a stack trace.
Running with Docker
The zenika/kotlin:1.4 image compiles a .kt file to a runnable JAR and executes it on the JVM. The -v $(pwd):/app mount lets the program create files (greetings.txt, numbers.txt) in your current directory.
| |
For the console-input example, add -i to keep stdin open and pipe a value in:
| |
Expected Output
Running IoOperations.kt produces:
No newline here. This ends the line.
Numbers: 42, 3.14
Pi to 2 decimals: 3.14
Padded: 42|
Name: Kotlin |
Hello from Kotlin
Second line
--- lines ---
1: Hello from Kotlin
2: Second line
Running BufferedIo.kt produces:
Read 5 lines
Running SafeRead.kt produces:
File not found: missing.txt
Piping Ada into EchoInput.kt produces:
What is your name? Hello, Ada!
Key Concepts
- Extension functions simplify I/O —
writeText,appendText,readText, andreadLinesonFilehandle opening and closing for you, replacing Java’s stream boilerplate. readLine()returns a nullableString?— Kotlin forces you to handle end-of-file, and helpers likeisNullOrBlank()andtoIntOrNull()make that safe and concise.useguarantees cleanup — it closes anyCloseable(writers, readers) after the block finishes, even on exceptions, just like try-with-resources.useLinesstreams lazily — read huge files without loading them entirely into memory, then let the resource close automatically.- Formatted output uses
printfspecifiers — call"%.2f".format(x)for decimals,%5dfor width, and%-10sfor left alignment. - I/O errors are exceptions — wrap file reads in
try/catchforFileNotFoundExceptionand related types to fail gracefully. - Full JVM interop — anything in Java’s
java.ioandjava.niois available, so you never outgrow Kotlin’s concise helpers.
Comments
Loading comments...
Leave a Comment