8.2 Line-by-Line Reading and Processing
Reading a whole file is simple, but real files can be large. If a log file has millions of lines, loading it all into memory is wasteful. Line-by-line reading processes one line at a time.
BufferedReader
BufferedReader reads text efficiently by keeping a buffer of characters. It is commonly created with Files.newBufferedReader().
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class ReadLinesDemo {
public static void main(String[] args) throws IOException {
Path path = Path.of("quotes.txt");
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
}reader.readLine() returns the next line without the line break. When there are no more lines, it returns null.
The try (...) { ... } syntax is try-with-resources. It automatically closes reader when the block ends, even if an exception happens.
Scanner for Token-Based Reading
Scanner can read a file token by token, line by line, or number by number. It is friendly for beginner parsing, but BufferedReader is usually faster for large files.
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;
public class ScannerFileDemo {
public static void main(String[] args) throws IOException {
Path path = Path.of("numbers.txt");
try (Scanner scanner = new Scanner(path, StandardCharsets.UTF_8)) {
int total = 0;
while (scanner.hasNextInt()) {
total += scanner.nextInt();
}
System.out.println("Total: " + total);
}
}
}Use Scanner when the file format is simple and token-based. Use BufferedReader when you want full control over each line.
Parsing Words
The program below reads quotes.txt, removes punctuation around each word, and writes each cleaned word into words.txt. In this example, quotes.txt contains:
Talk is cheap. Show me the code.
Code never lies, comments sometimes do.
Stay Hungry Stay Foolish.import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
public class WordExtractor {
static String cleanWord(String word) {
return word.replaceAll("^[\\p{Punct}]+|[\\p{Punct}]+$", "");
}
public static void main(String[] args) throws IOException {
Path input = Path.of("quotes.txt");
Path output = Path.of("words.txt");
try (
BufferedReader reader = Files.newBufferedReader(input, StandardCharsets.UTF_8);
BufferedWriter writer = Files.newBufferedWriter(output, StandardCharsets.UTF_8)
) {
String line;
while ((line = reader.readLine()) != null) {
String[] words = line.split("\\s+");
for (String word : words) {
String cleaned = cleanWord(word);
if (!cleaned.isEmpty()) {
writer.write(cleaned);
writer.newLine();
}
}
}
}
}
}Two resources are opened in the same try-with-resources header. Java closes both automatically, in reverse order.
After the program runs, words.txt becomes:
Talk
is
cheap
Show
me
the
code
Code
never
lies
comments
sometimes
do
Stay
Hungry
Stay
Foolish