Reading Files in Kotlin

Reading and writing files are basic tasks needed for many Kotlin programs. First we’ll look at some examples of reading files.

import java.io.File
import java.io.BufferedReader

// Reading files requires checking most calls for errors.
// This helper will streamline our error checks below.
fun check(condition: Boolean, message: String = "An error occurred") {
    if (!condition) {
        throw IllegalStateException(message)
    }
}

fun main() {
    // Perhaps the most basic file reading task is
    // slurping a file's entire contents into memory.
    val dat = File("/tmp/dat").readText()
    println(dat)

    // You'll often want more control over how and what
    // parts of a file are read. For these tasks, start
    // by opening a file to obtain a File object.
    val f = File("/tmp/dat")

    // Read some bytes from the beginning of the file.
    // Allow up to 5 to be read but also note how many
    // actually were read.
    val b1 = ByteArray(5)
    val n1 = f.inputStream().use { it.read(b1) }
    check(n1 != -1)
    println("${n1} bytes: ${String(b1, 0, n1)}")

    // You can also seek to a known location in the file
    // and read from there.
    f.inputStream().use { input ->
        input.skip(6)
        val b2 = ByteArray(2)
        val n2 = input.read(b2)
        check(n2 != -1)
        println("$n2 bytes @ 6: ${String(b2, 0, n2)}")
    }

    // The buffered reader provides more efficient reading for larger files
    // and additional reading methods.
    BufferedReader(f.reader()).use { reader ->
        val b4 = CharArray(5)
        val n4 = reader.read(b4)
        check(n4 != -1)
        println("5 bytes: ${String(b4, 0, n4)}")
    }
}

To run the program:

$ echo "hello" > /tmp/dat
$ echo "kotlin" >> /tmp/dat
$ kotlin reading-files.kt
hello
kotlin
5 bytes: hello
2 bytes @ 6: ko
5 bytes: hello

In this Kotlin version:

  1. We use File class for file operations.
  2. Instead of os.ReadFile, we use File("/tmp/dat").readText().
  3. We use inputStream() and BufferedReader for more controlled reading.
  4. Kotlin’s use function is utilized for automatic resource management (similar to Java’s try-with-resources).
  5. We don’t have direct equivalents for Seek, so we use skip method of InputStream to move to a specific position.
  6. Error handling is done via exceptions rather than returning error values.

Note that Kotlin provides more idiomatic ways to read files, such as File.readLines() or File.useLines {}, which weren’t shown here to keep the example closer to the original structure.

Next, we’ll look at writing files.