CodeGym /Courses /JAVA 25 SELF /Reading text files: line by line and all at once

Reading text files: line by line and all at once

JAVA 25 SELF
Level 36 , Lesson 1
Available

1. Reading a file line by line: BufferedReader and friends

Previously we looked at byte-by-byte reading: it’s convenient for working with binary formats, but for text it’s awkward. A file consists of characters that depend on the charset. That’s why Java offers convenient “wrappers” — FileReader, BufferedReader, and other classes that turn a stream of bytes into a stream of characters and lines.

Imagine a text file — whether it’s a program log, a list of users, or even the huge novel “War and Peace”. Sometimes you need to quickly read the entire file, sometimes to go through it line by line, and sometimes to extract one specific line.

In Java there are several ways to do this, and the choice depends on the file size and the task. If you need to process a file one line at a time (for example, count lines or find an entry), use line-by-line reading. And if the file is small, you can load it entirely into memory and work with it as a list of lines.

Why is line-by-line reading good?

For large files, line-by-line reading saves you from memory problems. Loading a gigabyte-size log into memory is a bad idea — you’re likely to hit an OutOfMemoryError. Reading the file line by line, however, can be done with minimal overhead, even if it’s hundreds of megabytes.

How is it done in Java?

The most classic way is to use BufferedReader (or its relatives) and the readLine() method.

import java.io.*;

public class ReadLinesDemo {
    public static void main(String[] args) {
        String fileName = "example.txt";

        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            int lineNumber = 1;
            while ((line = reader.readLine()) != null) {
                System.out.printf("%3d: %s%n", lineNumber, line);
                lineNumber++;
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

Here we open the file for reading and use readLine() to read one line at a time until we reach the end (null). After that we print each line with its number.

Briefly about try-with-resources

See the try (...) { ... } construct? That’s try-with-resources. It guarantees that the file will be closed even if an error occurs in the middle of reading. You don’t need to call close() manually: closing happens automatically, even with catch/finally.

Why do you need BufferedReader?

BufferedReader reads not one character at a time, but in blocks (usually 8192 bytes), which speeds up file I/O. In addition, it has a convenient readLine() method that returns a line up to the line break.

What buffer size should you choose?

Typically, BufferedReader uses a buffer of 8192 bytes (8 KB) — that’s enough for most tasks. If you read very long lines (for example, about 100_000 characters), you can increase the buffer:

BufferedReader reader = new BufferedReader(new FileReader(fileName), 65536); // 64 KB buffer

But for typical tasks, the default size is perfect.

2. Reading an entire file: Files.readAllLines and Files.readString

If the file is small (for example, up to 1020 MB), it’s convenient to load it all at once. For example, if you need to quickly get the list of lines, analyze the text, or send it over the network.

Modern way: Files.readAllLines

Since Java 7, the convenient Files class appeared with lots of useful methods.

import java.nio.file.*;
import java.io.IOException;
import java.util.List;

public class ReadAllLinesDemo {
    public static void main(String[] args) {
        Path path = Path.of("example.txt");

        try {
            List<String> lines = Files.readAllLines(path);
            for (int i = 0; i < lines.size(); i++) {
                System.out.printf("%3d: %s%n", i + 1, lines.get(i));
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

Here the Files.readAllLines(path) method returns a list of lines (List<String>). You can work with this list like a regular collection: search, sort, filter.

Newer: Files.readString (Java 11+)

If you need the whole file as a single string (for example, to search for a substring or to send as JSON), use Files.readString:

import java.nio.file.*;
import java.io.IOException;

public class ReadStringDemo {
    public static void main(String[] args) {
        Path path = Path.of("example.txt");

        try {
            String content = Files.readString(path);
            System.out.println("File contents:");
            System.out.println(content);
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

What about character encoding?

By default, Files.readAllLines and Files.readString use your platform default charset. If the file is encoded differently (for example, Windows-1251), specify it explicitly:

List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
String content = Files.readString(path, StandardCharsets.UTF_8);

3. Comparison of approaches: when to use which

Approach When to use Advantages Disadvantages
BufferedReader.readLine()
Large files, line-by-line processing Memory-efficient, flexible Only line-based reading
Files.readAllLines()
Small and medium files Immediate list of lines, simple For large files — OutOfMemoryError
Files.readString()
Small files, need the whole text Entire content as a single string No line splitting

Recommendation:
— If the file is small — use Files.readAllLines or Files.readString.
— If the file is large or you don’t know its size — use BufferedReader.readLine().

4. Practical tasks: examples and walkthrough

Example 1. Counting lines in a large file

Suppose you need to know how many lines are in a huge file (for example, a server log).

import java.io.*;

public class LineCount {
    public static void main(String[] args) {
        String fileName = "biglog.txt";
        int lineCount = 0;

        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            while (reader.readLine() != null) {
                lineCount++;
            }
            System.out.println("Total lines in file: " + lineCount);
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

Example 2. Searching lines by content

Find all lines that contain the word “error” (case-insensitive):

import java.io.*;

public class FindErrorLines {
    public static void main(String[] args) {
        String fileName = "biglog.txt";
        String keyword = "error";

        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            int lineNumber = 1;
            while ((line = reader.readLine()) != null) {
                if (line.toLowerCase().contains(keyword)) {
                    System.out.printf("%3d: %s%n", lineNumber, line);
                }
                lineNumber++;
            }
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }
}

Example 3. Loading configuration from a small file

File config.txt:

host=localhost
port=8080
mode=dev

Read it entirely and parse into key–value pairs:

import java.nio.file.*;
import java.util.*;

public class ConfigLoader {
    public static void main(String[] args) throws Exception {
        Path path = Path.of("config.txt");
        List<String> lines = Files.readAllLines(path);

        Map<String, String> config = new HashMap<>();
        for (String line : lines) {
            if (line.trim().isEmpty() || line.startsWith("#")) continue; // skip empty lines and comments
            String[] parts = line.split("=", 2);
            if (parts.length == 2) {
                config.put(parts[0].trim(), parts[1].trim());
            }
        }

        System.out.println("Loaded configuration: " + config);
    }
}

5. Common mistakes when reading text files

Mistake #1: Attempting to read a binary file as text. If you open an image or archive via BufferedReader or Files.readAllLines, you’ll get garbage and risk an OutOfMemoryError. For binary files use InputStream!

Mistake #2: Not handling exceptions. Files can be deleted, moved, or locked. Always wrap reading in try-catch and inform the user about problems.

Mistake #3: Ignoring character encoding. If your text is in Russian and you read the file without specifying the charset, you can get “?????”. Use StandardCharsets.UTF_8 or the charset you need.

Mistake #4: Forgetting to close the stream. If you don’t close a file, it can remain locked until the program ends. Always use try-with-resources.

Mistake #5: Using read() instead of readLine() for text files. The read() method reads one character at a time — it’s slow and inconvenient for lines. For text, use readLine() or the Files methods.

1
Task
JAVA 25 SELF, level 36, lesson 1
Locked
Merging the Great Saga Fragments 📖
Merging the Great Saga Fragments 📖
1
Task
JAVA 25 SELF, level 36, lesson 1
Locked
Finding common secrets in spy dossiers 🕵️
Finding common secrets in spy dossiers 🕵️
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION