JavaRush /Курсы /JAVA 25 SELF /Чтение текстовых файлов: построчно, целиком

Чтение текстовых файлов: построчно, целиком

JAVA 25 SELF
36 уровень , 1 лекция
Открыта

1. Чтение файла построчно: BufferedReader и компания

Ранее мы уже знакомились с побайтовым чтением: это удобно для работы с бинарными форматами, но для текста такой подход неудобен. Файл состоит из символов, которые зависят от кодировки. Поэтому Java предлагает удобные «надстройки» — FileReader, BufferedReader и другие классы, которые превращают поток байтов в поток символов и строк.

Представьте текстовый файл — будь то лог работы программы, список пользователей или даже огромный роман «Война и мир». Иногда нужно быстро прочитать весь файл целиком, иногда — пройтись по нему построчно, а иногда — вытащить одну конкретную строку.

В Java есть несколько способов это сделать, и выбор зависит от размера файла и задачи. Если нужно обработать файл по одной строке (например, подсчитать количество строк или найти запись), используют построчное чтение. А если файл небольшой — его можно загрузить в память целиком и работать с ним как со списком строк.

Почему построчно — это хорошо?

Для больших файлов построчное чтение спасает от проблем с памятью. Загружать в память гигабайтный лог — плохая идея: велик шанс нарваться на OutOfMemoryError. А вот считывать файл строка за строкой можно без особых затрат, даже если он весит сотни мегабайт.

Как это делается в Java?

Самый классический способ — использовать BufferedReader (или его родственников) и метод readLine().

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("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

Здесь мы открываем файл для чтения и с помощью readLine() читаем по одной строке, пока не дойдём до конца (null). После этого выводим каждую строку с номером.

Кратко о try-with-resources

Видите конструкцию try (...) { ... }? Это try-with-resources. Она гарантирует, что файл закроется, даже если в середине чтения случится ошибка. Вам не нужно вручную вызывать close(): закрытие произойдёт автоматически, даже при catch/finally.

Зачем нужен BufferedReader?

BufferedReader читает не по одному символу, а целыми блоками (обычно по 8192 байта), что ускоряет работу с файлами. Кроме того, у него есть удобный метод readLine(), который возвращает строку сразу до символа перевода строки.

Какой буфер выбрать?

Обычно BufferedReader использует буфер размером 8192 байта (8 КБ) — этого достаточно для большинства задач. Если вы читаете очень длинные строки (например, по 100_000 символов), буфер можно увеличить:

BufferedReader reader = new BufferedReader(new FileReader(fileName), 65536); // 64 КБ буфер

Но для обычных задач стандартный размер подходит идеально.

2. Чтение файла целиком: Files.readAllLines и Files.readString

Если файл небольшой (например, до 1020 МБ), его удобно загрузить целиком. Например, если нужно быстро получить список всех строк, проанализировать текст или отправить его по сети.

Современный способ: Files.readAllLines

С Java 7 появился удобный класс Files с кучей полезных методов.

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("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

Здесь метод Files.readAllLines(path) возвращает список строк (List<String>). С этим списком можно работать как с обычной коллекцией: искать, сортировать, фильтровать.

Ещё современнее: Files.readString (Java 11+)

Если вам нужно получить весь файл одной строкой (например, для поиска подстроки или передачи в JSON), используйте 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("Содержимое файла:");
            System.out.println(content);
        } catch (IOException e) {
            System.out.println("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

А что с кодировкой?

По умолчанию методы Files.readAllLines и Files.readString используют стандартную кодировку вашей системы. Если файл записан в другой кодировке (например, Windows-1251), укажите её явно:

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

3. Сравнение подходов: когда какой использовать

Способ Когда использовать Преимущества Недостатки
BufferedReader.readLine()
Большие файлы, построчная обработка Экономит память, гибко Чтение только по строкам
Files.readAllLines()
Маленькие и средние файлы Сразу список строк, просто Для больших файлов — OutOfMemory
Files.readString()
Маленькие файлы, нужен весь текст Вся строка целиком Нет разбивки на строки

Рекомендация:
— Если файл небольшой — используйте Files.readAllLines или Files.readString.
— Если файл большой или вы не знаете его размер — используйте BufferedReader.readLine().

4. Практические задачи: примеры и разбор

Пример 1. Подсчёт строк в большом файле

Допустим, нужно узнать, сколько строк в огромном файле (например, логе сервера).

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("Всего строк в файле: " + lineCount);
        } catch (IOException e) {
            System.out.println("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

Пример 2. Поиск строки по содержимому

Ищем все строки, где встречается слово «ошибка» (case-insensitive):

import java.io.*;

public class FindErrorLines {
    public static void main(String[] args) {
        String fileName = "biglog.txt";
        String keyword = "ошибка";

        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("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

Пример 3. Загрузка конфигурации из небольшого файла

Файл config.txt:

host=localhost
port=8080
mode=dev

Читаем его целиком и разбираем на пары ключ-значение:

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; // пропускаем пустые и комментарии
            String[] parts = line.split("=", 2);
            if (parts.length == 2) {
                config.put(parts[0].trim(), parts[1].trim());
            }
        }

        System.out.println("Загруженная конфигурация: " + config);
    }
}

5. Типичные ошибки при чтении текстовых файлов

Ошибка №1: Попытка читать бинарный файл как текстовый. Если вы откроете изображение или архив через BufferedReader или Files.readAllLines, получите бессмысленные символы и риск OutOfMemoryError. Для бинарных файлов используйте InputStream!

Ошибка №2: Не обработали исключение. Файлы могут удалить, переместить, заблокировать. Всегда оборачивайте чтение в try-catch и информируйте пользователя о проблемах.

Ошибка №3: Игнорирование кодировки. Если у вас текст на русском, а вы читаете файл без указания кодировки, можно получить «?????». Используйте StandardCharsets.UTF_8 или нужную вам кодировку.

Ошибка №4: Забыли закрыть поток. Если не закрыть файл, он может остаться заблокированным до завершения программы. Всегда используйте try-with-resources.

Ошибка №5: Использование read() вместо readLine() для текстовых файлов. Метод read() читает по символу — это медленно и неудобно для строк. Для текста используйте readLine() или методы класса Files.

1
Задача
JAVA 25 SELF, 36 уровень, 1 лекция
Недоступна
Объединение фрагментов великой саги 📖
Объединение фрагментов великой саги 📖
1
Задача
JAVA 25 SELF, 36 уровень, 1 лекция
Недоступна
Поиск общих секретов в шпионских досье 🕵️
Поиск общих секретов в шпионских досье 🕵️
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ