/commands/kotlin/read-file-line-by-line
kotlin read a file line by line (readLines, useLines, forEachLine)
- tool
- Kotlin
- versions
- Kotlin 1.0+ (JVM)
- os
- any
In Kotlin/JVM, File("data.txt").readLines() returns all lines of a file as a List<String>, and File("data.txt").forEachLine { println(it) } processes them one at a time. For large files use useLines { lines -> ... }, which gives you a lazy Sequence<String> and closes the file when the block ends. All of them read UTF-8 by default and drop the line terminators.
Examples
import java.io.File
fun main() {
val file = File("data.txt")
// Small files: everything in memory as List<String>
val lines = file.readLines()
println("${lines.size} lines, first: ${lines.firstOrNull()}")
// Any size: one line at a time
file.forEachLine { line -> println(line.uppercase()) }
// Any size, with sequence operations; the file is closed after the block
val errors = file.useLines { seq -> seq.filter { "ERROR" in it }.count() }
println("$errors error lines")
// Whole file as one String
val text = file.readText()
println(text.length)
}Choosing a function
| Function | Returns | Use it when |
|---|---|---|
| File.readLines() | List<String> | The file is small and you need random access to lines |
| File.forEachLine { } | Unit | You only need to process each line once |
| File.useLines { seq -> } | Whatever the block returns | Large files with filter, map or take; the file is closed afterwards |
| File.readText() | String | You need the whole content as one string |
| File.bufferedReader().use { it.readLine() } | String? | Read only the first line, or full control over reading |
| generateSequence(::readLine) | Sequence<String> | Read standard input line by line |
Pitfalls
- Escaping the sequence. The sequence from
useLinesis only valid inside the block: returning it and iterating later fails because the reader is already closed. Turn it into a list (seq.toList()) or compute the result inside the block. - Missing files.
File("missing.txt").readLines()throwsjava.io.FileNotFoundException. Checkfile.exists()first or catch the exception. - Relative paths. A relative path is resolved against the working directory of the JVM, which for
./gradlew runis the subproject folder, not necessarily the folder you expect. Printfile.absolutePathwhen a file is not found. - Kotlin Multiplatform.
java.io.Fileexists only on the JVM (and Android); common code needs a library such as kotlinx-io or Okio. - Numbers in lines must be parsed, see convert a string to an Int.
Confirm it worked
Print lines.size and compare it with the line count your editor shows for the file. A final newline does not add an empty entry, but blank lines inside the file come back as empty strings; drop them with lines.filter { it.isNotBlank() } if they do not matter.
FAQ
Which encoding does readLines use?
UTF-8 by default. Pass another charset when the file uses one, for example File(path).readLines(Charsets.ISO_8859_1).
Are the line endings included in each line?
No. The functions split on \n, \r\n and \r and return the lines without the terminators, so files with Windows line endings need no extra handling.
Why do I get Unresolved reference: readLines?
readLines, useLines and forEachLine are extension functions on java.io.File in kotlin.io. Import java.io.File and call them on a File, not on a String path.