Kotlin File and I/O Operations

File and I/O operations let your program read data from storage, write data to storage, and communicate through streams. On desktop and server applications, you work with the filesystem directly. On Android, you use platform-specific APIs — but the Kotlin concepts remain the same.

Reading a File

import java.io.File

val file = File("notes.txt")

// Read entire file as a single String
val content = file.readText()
println(content)

// Read file line by line as a List
val lines = file.readLines()
for (line in lines) {
    println(line)
}

// Read one line at a time (memory-efficient for large files)
file.forEachLine { line ->
    println(line)
}

Diagram — File Reading Options

notes.txt on disk:
┌─────────────────────────────┐
│Line 1: Kotlin is fun        │
│Line 2: Study every day      │
│Line 3: Build real projects  │
└─────────────────────────────┘

readText()  → "Line 1: Kotlin...\nLine 2:...\nLine 3:..."  (one String)
readLines() → ["Line 1: Kotlin...", "Line 2:...", "Line 3:..."] (List)
forEachLine → processes one line at a time (stream, low memory)

Writing to a File

val output = File("output.txt")

// Write (overwrites existing content)
output.writeText("Hello, Kotlin!\n")

// Append (adds to existing content)
output.appendText("Second line\n")

// Write multiple lines
val data = listOf("Item 1", "Item 2", "Item 3")
output.writeText(data.joinToString("\n"))

println(output.readText())
// Item 1
// Item 2
// Item 3

File Properties and Checks

val f = File("data.txt")

println(f.exists())         // true or false
println(f.isFile())         // true (not a directory)
println(f.isDirectory())    // false
println(f.name)             // data.txt
println(f.nameWithoutExtension) // data
println(f.extension)        // txt
println(f.length())         // file size in bytes
println(f.absolutePath)     // full path on disk
println(f.parent)           // parent directory path

Creating and Deleting Files and Directories

// Create a new empty file
val newFile = File("newFile.txt")
newFile.createNewFile()

// Create directory
val dir = File("myFolder")
dir.mkdir()           // creates single directory
dir.mkdirs()          // creates all missing parent directories too

// Delete
newFile.delete()      // deletes file
dir.deleteRecursively() // deletes directory and all its contents

Listing Directory Contents

val folder = File(".")    // current directory

// List names only
val names = folder.list()
names?.forEach { println(it) }

// List as File objects
val files = folder.listFiles()
files?.forEach { file ->
    val type = if (file.isDirectory) "[DIR] " else "[FILE]"
    println("$type ${file.name}")
}

// Filter — only .kt files
val kotlinFiles = folder.listFiles { f -> f.extension == "kt" }

Using BufferedReader and BufferedWriter

Buffered I/O reads or writes large chunks at once instead of one byte at a time. This is much faster for large files.

// Buffered reading
File("bigfile.txt").bufferedReader().use { reader ->
    var line: String?
    while (reader.readLine().also { line = it } != null) {
        println(line)
    }
}

// Buffered writing
File("output.txt").bufferedWriter().use { writer ->
    writer.write("Line 1")
    writer.newLine()
    writer.write("Line 2")
}

The use block automatically closes the reader or writer when done, even if an exception occurs. This prevents resource leaks.

Working with Paths

import java.nio.file.Paths
import java.nio.file.Files

val path = Paths.get("docs", "kotlin", "notes.txt")
println(path)   // docs/kotlin/notes.txt

// Create nested directories
Files.createDirectories(path.parent)

// Write with NIO
Files.writeString(path, "Written with NIO")

// Read with NIO
val content = Files.readString(path)
println(content)

Kotlin File Extension Functions

Kotlin adds convenience extension functions to Java's File class.

val file = File("sample.txt")

// Walk directory tree
file.parentFile?.walk()?.forEach { f ->
    println(f.name)
}

// Copy file
val copy = File("sample_copy.txt")
file.copyTo(copy, overwrite = true)

// Move file (copy + delete original)
file.renameTo(File("moved.txt"))

// Read as bytes
val bytes: ByteArray = file.readBytes()
println("File size: ${bytes.size} bytes")

// Write bytes
File("binary.dat").writeBytes(bytes)

Diagram — I/O Hierarchy

Input Source                  Your Program              Output Target
─────────────                 ────────────              ─────────────
Keyboard    ─►  InputStream   ─►  Process  ─►  OutputStream  ─►  Screen
File        ─►  FileReader    ─►  Logic    ─►  FileWriter    ─►  File
Network     ─►  Socket        ─►  Logic    ─►  Socket        ─►  Network

Buffered layer wraps these for performance:
Raw source ─► BufferedReader ─► Your code reads lines efficiently

Leave a Comment

Your email address will not be published. Required fields are marked *