Kotlin
File I/O
Save and load data with File.
File saving for Library
This lesson adds file save and load methods to Library. save(path) writes each book's format output line by line to the file; load(path) reads the file and returns its content as a string. So the library data becomes persistent in a file.
fun save(path: String) {
val content = books.joinToString("\n") { it.format() }
File(path).writeText(content)
}
fun load(path: String): String = File(path).readText()
joinToString joins each book's format output with \n. writeText writes the result to the file; readText reads all content back. The File class comes from java.io.File; so import java.io.File is needed. For large libraries, line-by-line reading may be preferred instead.
The save and load pattern
save and load work together: save writes data to the file, load reads it back. This is useful to make data persist between program runs. The file path is given as a string; a relative path is resolved against the working directory.
val lib = Library()
lib.add(Book("Crime and Punishment", "Dostoyevsky", 1866, Fiction))
lib.save("library.txt")
println(lib.load("library.txt"))
Here a book is added, written to the file with save, then read back with load. The output is the format output that was written to the file. This pattern is common in small data-driven applications. For more complex data, JSON or CSV formats may be preferred; a topic for later.
Exercise Add save and load methods
The Book, Category and Library definitions are ready (Library has add and listAll). Add two methods to the Library class: fun save(path: String) whose body joins content with books.joinToString("\n") { it.format() } and writes with File(path).writeText(content). fun load(path: String): String whose body returns File(path).readText(). In main create val lib = Library(); add two books; call lib.save("library.txt"); print println(lib.load("library.txt")). Add the import java.io.File import at the top of the file.
Show example solution
import java.io.File
data class Book(val title: String, val author: String, val year: Int, val category: Category) {
fun format(): String = "$title - $author ($year) [${category.label()}]"
}
sealed class Category {
abstract fun label(): String
}
object Fiction : Category() {
override fun label() = "Fiction"
}
object NonFiction : Category() {
override fun label() = "Non-fiction"
}
class Library {
private val books = mutableListOf<Book>()
fun add(b: Book) { books.add(b) }
fun listAll(): List<Book> = books.toList()
fun save(path: String) {
val content = books.joinToString("\n") { it.format() }
File(path).writeText(content)
}
fun load(path: String): String {
return File(path).readText()
}
}
fun main() {
val lib = Library()
lib.add(Book("Crime and Punishment", "Dostoyevsky", 1866, Fiction))
lib.add(Book("Sapiens", "Harari", 2011, NonFiction))
lib.save("library.txt")
println(lib.load("library.txt"))
}
Test yourself
-
What does the save method write to the file?
- Only the first book
- The book count
- An empty string
- Each book's format output, line by line
Show answer
Each book's format output, line by line — save joins each book's format output with joinToString and writes it.
-
Write to the file
File(path).____(content)
Show answer
File(path).writeText(content)
-
Match the save/load parts
- fun save(path)
- Write method
- fun load(path)
- Read method
- joinToString
- Join
- writeText
- Writes to file
Next lesson: Putting it together