1 / 18

πŸ“ Reading & Writing Files in Kotlin

A Beginner's Guide to File I/O Operations


Master the fundamentals of file handling in Kotlin

πŸ€” What is File I/O?

File I/O stands for Input/Output operations on files.


Why do we need File I/O?

  • Save user data permanently
  • Load configuration settings
  • Process large datasets
  • Create logs and reports

πŸ“„ The File Class in Kotlin

In Kotlin, we use the java.io.File class to work with files.

Creating a File Object:

import java.io.File

// Different ways to create a File object
val file1 = File("myfile.txt")
val file2 = File("C:/Users/Documents/data.txt")
val file3 = File("folder", "filename.txt")
           

Note: Creating a File object doesn't create the actual file on disk - it just creates a reference to it!

πŸ”§ Basic File Operations

Before reading or writing, let's check some basic file properties:

import java.io.File

fun checkFile() {
    val file = File("example.txt")
    
    println("File exists: ${file.exists()}")
    println("Is file: ${file.isFile}")
    println("Is directory: ${file.isDirectory}")
    println("Can read: ${file.canRead()}")
    println("Can write: ${file.canWrite()}")
    println("File size: ${file.length()} bytes")
}

✍️ Writing to Files - Method 1: writeText()

The writeText() method is the simplest way to write text to a file.

import java.io.File

fun writeToFile() {
    val file = File("greeting.txt")
    val content = "Hello, Kotlin File I/O!"
    
    // This will create the file if it doesn't exist
    // and overwrite it if it does exist
    file.writeText(content)
    
    println("File written successfully!")
}

Important: writeText() will completely overwrite the file contents!

✍️ Writing to Files - Method 2: appendText()

Use appendText() to add content to the end of an existing file.

import java.io.File

fun appendToFile() {
    val file = File("log.txt")
    
    // Add new content to the end of the file
    file.appendText("First line\n")
    file.appendText("Second line\n")
    file.appendText("Third line\n")
    
    println("Content appended successfully!")
}

Result in log.txt:

First line
Second line
Third line

πŸ“ Writing Multiple Lines

For writing multiple lines, you can use lists with writeLines():

import java.io.File

fun writeMultipleLines() {
    val file = File("shopping_list.txt")
    val items = listOf(
        "Apples",
        "Bananas",
        "Milk",
        "Bread",
        "Eggs"
    )
    
    // Write all lines at once
    file.writeLines(items)
    
    println("Shopping list created!")
}

πŸ“– Reading Files - Method 1: readText()

The readText() method reads the entire file as a single string.

import java.io.File

fun readEntireFile() {
    val file = File("greeting.txt")
    
    if (file.exists()) {
        val content = file.readText()
        println("File content:")
        println(content)
    } else {
        println("File doesn't exist!")
    }
}

Best for: Small text files that fit comfortably in memory

πŸ“– Reading Files - Method 2: readLines()

The readLines() method reads the file as a list of strings, one per line.

import java.io.File

fun readFileLines() {
    val file = File("shopping_list.txt")
    
    if (file.exists()) {
        val lines = file.readLines()
        
        println("Shopping List:")
        lines.forEachIndexed { index, item ->
            println("${index + 1}. $item")
        }
    } else {
        println("Shopping list not found!")
    }
}

πŸ“š Reading Large Files

For large files, use forEachLine() to read line by line without loading everything into memory:

import java.io.File

fun readLargeFile() {
    val file = File("large_data.txt")
    var lineCount = 0
    
    if (file.exists()) {
        file.forEachLine { line ->
            lineCount++
            // Process each line individually
            if (line.contains("important")) {
                println("Found important line $lineCount: $line")
            }
        }
        println("Total lines processed: $lineCount")
    }
}

Memory Efficient: Only one line is in memory at a time!

⚠️ Exception Handling

File operations can fail! Always handle exceptions properly:

import java.io.File
import java.io.IOException

fun safeFileOperations() {
    val file = File("important.txt")
    
    try {
        // Attempt to read the file
        val content = file.readText()
        println("File content: $content")
        
        // Attempt to write to the file
        file.appendText("\nNew line added")
        println("Successfully updated file")
        
    } catch (e: IOException) {
        println("Error accessing file: ${e.message}")
    }
}

πŸ“ Working with Directories

You can also work with directories (folders) using the File class:

import java.io.File

fun workWithDirectories() {
    val directory = File("my_folder")
    
    // Create directory if it doesn't exist
    if (!directory.exists()) {
        directory.mkdir()  // Creates single directory
        // directory.mkdirs() // Creates nested directories
        println("Directory created!")
    }
    
    // List files in directory
    val files = directory.listFiles()
    files?.forEach { file ->
        println("Found: ${file.name}")
    }
}

πŸ—ΊοΈ File Paths and Navigation

Understanding file paths is crucial for file operations:

import java.io.File

fun explorePaths() {
    val file = File("documents/notes.txt")
    
    println("File name: ${file.name}")
    println("Parent directory: ${file.parent}")
    println("Absolute path: ${file.absolutePath}")
    println("Canonical path: ${file.canonicalPath}")
    
    // Working directory
    val currentDir = File(".").canonicalPath
    println("Current directory: $currentDir")
}

πŸ’‘ Practical Example - Simple Note App

import java.io.File
import java.time.LocalDateTime

class SimpleNoteApp {
    private val notesFile = File("notes.txt")
    
    fun addNote(note: String) {
        val timestamp = LocalDateTime.now()
        val entry = "[$timestamp] $note\n"
        notesFile.appendText(entry)
        println("Note added successfully!")
    }
    
    fun showAllNotes() {
        if (notesFile.exists()) {
            println("=== Your Notes ===")
            println(notesFile.readText())
        } else {
            println("No notes found!")
        }
    }
}

βœ… Best Practices

❌ Common Mistakes to Avoid

  • Not checking if file exists before reading
  • Using wrong path separators (use / or File.separator)
  • Forgetting exception handling
  • Loading huge files entirely into memory
  • Not handling file permissions issues

❌ Bad:

val content = File("file.txt").readText() // May crash!

βœ… Good:

val file = File("file.txt")
if (file.exists()) {
    val content = file.readText()
}

πŸ‹οΈ Exercise Challenge

Create a Simple To-Do List Manager

Your task: Build a program that can:

  • Add new tasks to a file
  • Display all tasks
  • Mark tasks as completed
  • Save tasks persistently

Starter Code Structure:

class TodoManager {
    private val todoFile = File("todo.txt")
    
    fun addTask(task: String) { /* Your code */ }
    fun showTasks() { /* Your code */ }
    fun completeTask(index: Int) { /* Your code */ }
}

πŸŽ‰ Summary

You've learned the fundamentals of file I/O in Kotlin!

Key Concepts Covered:

Next Steps: Practice with real projects, explore advanced I/O topics like BufferedReader/Writer, and learn about working with different file formats!