How to read a file line by line
Short answer
Suppose there is a file log.txt:
INFO start
ERROR disk full
INFO retry
ERROR timeoutFiles.lines() reads the file lazily, one line at a time. The stream keeps the file open, so wrap it in a try-with-resources — it closes the file for you:
void main() throws IOException {
try (Stream<String> lines = Files.lines(Path.of("log.txt"))) {
lines.filter(line -> line.startsWith("ERROR")).forEach(IO::println);
}
}Output:
ERROR disk full
ERROR timeoutBufferedReader
The classic way is to read in a loop until readLine() returns null:
void main() throws IOException {
try (BufferedReader reader = Files.newBufferedReader(Path.of("log.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
IO.println(line.length() + " " + line);
}
}
}Output:
10 INFO start
15 ERROR disk full
10 INFO retry
13 ERROR timeoutWith line numbers
Keep a counter in the loop:
void main() throws IOException {
try (var reader = Files.newBufferedReader(Path.of("log.txt"))) {
int number = 0;
String line;
while ((line = reader.readLine()) != null) {
number++;
if (line.contains("timeout")) {
IO.println("line " + number + ": " + line);
}
}
}
}Output:
line 4: ERROR timeoutCommon mistake
Using Files.lines() without try. The file stays open until garbage collection; in a long-running program open files pile up and the system stops opening new ones. Always write try (var lines = Files.lines(...)).
Functions used in this recipe
- Files.lines() — Reads a file lazily as a stream of lines, without loading it into memory.
- BufferedReader — Reads text line by line with buffering — the classic way to process large files.
- Files.readAllLines() — Reads a text file into a list of lines.