Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Чтение и запись файлов

Большинство задач с файлами сводится к двум действиям: записать текст и прочитать его обратно. Класс Files делает это одной строкой. Все методы работают в кодировке UTF-8 — она понимает любые языки, включая русский.

Записать и прочитать строку

Files.writeString записывает строку в файл, создавая его при необходимости. Files.readString читает весь файл в одну строку:

void main() throws IOException {
    Path path = Path.of("greeting.txt");
 
    Files.writeString(path, "Привет, Анна!");
    String text = Files.readString(path);
 
    IO.println(text);
}

Результат:

Привет, Анна!

Оба метода могут выбросить проверяемое IOException, поэтому у main стоит throws IOException. Если файл уже существовал, writeString полностью заменит его содержимое.

Построчно

Часто файл удобнее обрабатывать по строкам. Files.write записывает список строк, добавляя после каждой перевод строки, а Files.readAllLines возвращает строки списком:

void main() throws IOException {
    Path path = Path.of("shopping.txt");
    Files.write(path, List.of("молоко", "хлеб", "сыр"));
 
    List<String> lines = Files.readAllLines(path);
    IO.println("Строк: " + lines.size());
    for (int i = 0; i < lines.size(); i++) {
        IO.println((i + 1) + ". " + lines.get(i));
    }
}

Результат:

Строк: 3
1. молоко
2. хлеб
3. сыр

Дописать в конец

Чтобы добавить текст, не стирая старый, передайте опцию StandardOpenOption.APPEND. Вместе с ней обычно указывают CREATE — создать файл, если его ещё нет:

void main() throws IOException {
    Path log = Path.of("app.log");
    Files.deleteIfExists(log);
 
    for (String event : List.of("запуск", "вход Олега", "выход")) {
        Files.writeString(log, event + "\n", StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }
 
    IO.print(Files.readString(log));
}

Результат:

запуск
вход Олега
выход

Большие файлы

readAllLines загружает весь файл в память. Для больших файлов лучше Files.lines: он возвращает поток строк и читает файл по мере надобности. Поток держит файл открытым, поэтому его закрывают через try-with-resources:

void main() throws IOException {
    Path path = Path.of("sales.csv");
    Files.write(path, List.of("Анна,120", "Олег,80", "Ира,200", "Олег,40"));
 
    try (Stream<String> lines = Files.lines(path)) {
        int total = lines
                .filter(line -> line.startsWith("Олег"))
                .mapToInt(line -> Integer.parseInt(line.split(",")[1]))
                .sum();
        IO.println("Продажи Олега: $" + total);
    }
}

Результат:

Продажи Олега: $120

Буферизованные потоки

Когда текст пишут по частям — например, в цикле, — используют BufferedWriter. Он копит данные в памяти и записывает их на диск крупными порциями, что быстрее. Пару ему составляет BufferedReader:

void main() throws IOException {
    Path path = Path.of("squares.txt");
 
    try (BufferedWriter writer = Files.newBufferedWriter(path)) {
        for (int i = 1; i <= 3; i++) {
            writer.write(i + " в квадрате = " + i * i);
            writer.newLine();
        }
    }
 
    try (BufferedReader reader = Files.newBufferedReader(path)) {
        IO.println(reader.readLine());
        IO.println(reader.readLine());
    }
}

Результат:

1 в квадрате = 1
2 в квадрате = 4

Частая ошибка

Чтение несуществующего файла выбрасывает NoSuchFileException — например, из-за опечатки в имени или запуска программы из другой папки:

void main() throws IOException {
    Files.writeString(Path.of("report.txt"), "Отчёт");
 
    IO.println(Files.readString(Path.of("reprot.txt")));
}

Результат:

Exception in thread "main" java.nio.file.NoSuchFileException: reprot.txt
	at Main.main(Main.java:4)

Если файл может отсутствовать, проверьте его через Files.exists или перехватите NoSuchFileException. А чтобы понять, где программа ищет относительный путь, выведите Path.of("").toAbsolutePath().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.