FileWriter: примеры (JAVA)

Разбор использования FileWriter в Java
Раздел: Потоки ввода-вывода (Streams) символьные
FileWriter(File file, String fileName, boolean append)

Общее описание FileWriter в Java

Класс FileWriter служит для записи символьных данных в файл. Он является подклассом java.io.OutputStreamWriter и ориентирован на простую запись текста с использованием кодировки по умолчанию платформы. Обычно применяется для быстрого создания или дозаписи текстовых файлов, когда не требуется явная установка кодировки или буферизация.

Конструкторы и их параметры:

  • FileWriter(String fileName) - открывает файл по имени; если файл не существует, создаётся; если существует, содержимое перезаписывается. Параметр: fileName (не null). Может бросить IOException или NullPointerException.
  • FileWriter(String fileName, boolean append) - второй параметр append указывает дозапись в конец файла (true) или перезапись (false).
  • FileWriter(File file) - аналогично первому, принимает объект File.
  • FileWriter(File file, boolean append) - вариант с флагом дозаписи.
  • FileWriter(FileDescriptor fd) - создаёт писатель из уже открытого файлового дескриптора; полезно при работе с нативными дескрипторами.

Основные методы (наследуемые/реализуемые) и их поведение:

  • void write(int c) - записать один символ (целое значение символа).
  • void write(char[] cbuf) - записать массив символов.
  • void write(char[] cbuf, int off, int len) - записать часть массива с смещением и длиной.
  • void write(String str) - записать всю строку.
  • void write(String str, int off, int len) - записать часть строки.
  • Writer append(CharSequence csq) - реализует интерфейс Appendable, возвращает тот же объект писателя для цепочек вызовов.
  • Writer append(CharSequence csq, int start, int end) и Writer append(char c) - дополнительные перегрузки.
  • void flush() - сбрасывает буферы в ОС; полезно для гарантии сохранения данных до закрытия.
  • void close() - закрывает поток; после закрытия дальнейшие операции вызывают исключение.

Возвращаемые значения: методы записи и закрытия имеют тип void, методы append возвращают ссылку на Writer (обычно сам FileWriter) для удобства построения цепочек.

Исключения и особенности:

  • Конструкторы и методы записи бросают IOException при проблемах с файловой системой.
  • FileWriter использует кодировку по умолчанию платформы; при необходимости конкретной кодировки следует применять OutputStreamWriter с указанием Charset или использовать API Files.newBufferedWriter.
  • Класс не обеспечивает внутренней синхронизации; многопоточный доступ требует внешней синхронизации.
  • Для повышения производительности часто оборачивается в BufferedWriter или PrintWriter.

Короткие примеры использования FileWriter

Пример 1. Простая запись строки (перезапись файла).

import java.io.FileWriter;
import java.io.IOException;

public class Example1 {
    public static void main(String[] args) throws IOException {
        try (FileWriter fw = new FileWriter("out1.txt")) {
            fw.write("Привет, FileWriter!\n");
        }
    }
}
Результат: файл out1.txt содержит текст "Привет, FileWriter!" и перевод строки.

Пример 2. Дозапись в существующий файл.

try (FileWriter fw = new FileWriter("out1.txt", true)) {
    fw.write("Дополнительная строка\n");
}
Результат: в конце out1.txt добавлена строка "Дополнительная строка".

Пример 3. Запись подмножества символов и строки.

try (FileWriter fw = new FileWriter("out2.txt")) {
    char[] arr = {'а','б','в','г','д'};
    fw.write(arr, 1, 3); // запишет 'бвг'
    fw.write("12345", 1, 3); // запишет '234'
}
Результат: out2.txt содержит "бвг234".

Пример 4. Использование FileDescriptor (встроенный дескриптор).

import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.FileWriter;

try (FileOutputStream fos = new FileOutputStream("out3.txt")) {
    FileDescriptor fd = fos.getFD();
    try (FileWriter fw = new FileWriter(fd)) {
        fw.write("Запись через FileDescriptor\n");
    }
}
Результат: out3.txt содержит строку "Запись через FileDescriptor".

Альтернативы внутри Java и их особенности

  • BufferedWriter - оборачивается вокруг Writer (включая FileWriter) для буферизации; повышает производительность при множественных мелких записях.
  • OutputStreamWriter (в комбинации с FileOutputStream) - позволяет явно указать кодировку, тогда как FileWriter использует кодировку по умолчанию.
  • PrintWriter - удобен для форматированного вывода (методы print/printf/println); предоставляет опцию автосброса при необходимости.
  • java.nio.file.Files.newBufferedWriter - современный NIO API с возможностью указать Charset и опции открытия файла; предпочтителен при работе с NIO.
  • Files.write - удобен для однократной записи небольших массивов байтов/строк; выполняет всю операцию в один вызов.

Когда отдавать предпочтение:

  • Если нужна явная кодировка - OutputStreamWriter или Files.newBufferedWriter.
  • При большом объёме операций записи - оборачивать в BufferedWriter.
  • Для форматированного вывода - PrintWriter.
  • Для единоразовой записи небольших наборов данных - Files.write.

Аналоги в других языках и краткие примеры

PHP

// file_put_contents
file_put_contents('php_out.txt', "Привет из PHP\n");
Результат: php_out.txt содержит строку "Привет из PHP".

JavaScript (Node.js)

// синхронная запись
const fs = require('fs');
fs.writeFileSync('node_out.txt', 'Привет из Node\n', 'utf8');
Результат: node_out.txt содержит "Привет из Node".

Python

# с указанием кодировки
with open('py_out.txt', 'w', encoding='utf-8') as f:
    f.write('Привет из Python\n')
Результат: py_out.txt содержит "Привет из Python".

C#

using System.IO;
File.WriteAllText("cs_out.txt", "Привет из C#\n");
Результат: cs_out.txt содержит "Привет из C#".

Go

package main
import (
    "os"
)
func main() {
    os.WriteFile("go_out.txt", []byte("Привет из Go\n"), 0644)
}
Результат: go_out.txt содержит "Привет из Go".

Lua

local f = io.open('lua_out.txt', 'w')
f:write('Привет из Lua\n')
f:close()
Результат: lua_out.txt содержит "Привет из Lua".

Kotlin

import java.io.File
File("kt_out.txt").writeText("Привет из Kotlin\n")
Результат: kt_out.txt содержит "Привет из Kotlin".

SQL

Прямых аналогов записи файла в SQL нет; обычно экспорт выполняется через утилиты СУБД (COPY в PostgreSQL) или с использованием языков хостинга (см. примеры выше).

Типичные ошибки при работе с FileWriter

1. NullPointerException при передаче null в конструктор.

new FileWriter((String) null);
Исключение: java.lang.NullPointerException

2. IOException при попытке открыть директорию или при отсутствии прав.

try (FileWriter fw = new FileWriter("/etc")) {
    fw.write("test");
}
Исключение: java.io.IOException: Is a directory (или сообщение ОС: "Access is denied")

3. PermissionDenied при отсутствии прав на запись.

// запуск в защищённой папке
try (FileWriter fw = new FileWriter("C:\\Windows\\system32\\file.txt")) {
    fw.write("x");
}
Исключение: java.io.IOException: Permission denied (в Unix) или Access is denied (в Windows)

4. Потеря специфичной кодировки при использовании FileWriter.

try (FileWriter fw = new FileWriter("utf_out.txt")) {
    fw.write("текст с символами € и другие\n");
}
Результат: возможно некорректное отображение символов, если кодировка по умолчанию не поддерживает эти символы. Рекомендуется явное задание Charset.

5. Неэффективность при частых мелких операциях записи без буфера.

for (int i = 0; i < 10000; i++) fw.write("a");
Результат: медленная работа; рекомендация - использовать BufferedWriter.

Изменения и рекомендации по использованию в последних версиях Java

Класс FileWriter не подвергался существенным изменениям в последних релизах; его поведение сохраняет совместимость. Основные тенденции платформы следующие:

  • Рекомендуется применять NIO API (java.nio.file.Files) и явное указание Charset для избежания проблем с кодировками.
  • При возможности предпочтение отдаётся Files.newBufferedWriter или Files.write для более явного управления опциями открытия файла.
  • Поддержка try-with-resources (начиная с Java 7) делает управление ресурсами более безопасным.

Расширенные и редкие сценарии применения FileWriter

Пример 1. Буферизированная запись большого файла с прогрессом.

Пример java
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BigWrite {
    public static void main(String[] args) throws IOException {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("big.txt"), 16 * 1024)) {
            for (int i = 0; i < 500_000; i++) {
                bw.write("Строка номер " + i + "\n");
                if (i % 100_000 == 0) {
                    System.out.println("Прогресс: " + i);
                }
            }
        }
    }
}
Результат: файл big.txt содержит 500000 строк; в консоль выводятся стадии прогресса (0, 100000, 200000...).

Пример 2. Атомарическая замена файла через временный файл.

Пример java
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

Path target = Path.of("atomic.txt");
Path temp = Files.createTempFile(target.getParent(), "tmp", ".tmp");
try (FileWriter fw = new FileWriter(temp.toFile())) {
    fw.write("Новый содержимый файл\n");
}
Files.move(temp, target, java.nio.file.StandardCopyOption.REPLACE_EXISTING, java.nio.file.StandardCopyOption.ATOMIC_MOVE);
Результат: файл atomic.txt заменяется атомарно новым содержимым, минимизируется время, когда файла нет или он частично записан.

Пример 3. Запись через GZIP с текстовой кодировкой (сжатая текстовая логика).

Пример java
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.util.zip.GZIPOutputStream;

try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
        new GZIPOutputStream(new FileOutputStream("log.txt.gz")), java.nio.charset.StandardCharsets.UTF_8))) {
    bw.write("Сжатый лог\n");
}
Результат: создаётся сжатый файл log.txt.gz, содержащий текст в кодировке UTF-8.

Пример 4. Совместная запись с блокировкой файла (FileLock).

Пример java
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.StandardCharsets;

try (FileOutputStream fos = new FileOutputStream("locked.txt", true);
     FileChannel ch = fos.getChannel();
     OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {
    try (FileLock lock = ch.lock()) { // блокировка на время записи
        osw.write("Запись с блокировкой\n");
        osw.flush();
    }
}
Результат: запись добавляется с полученной эксклюзивной блокировкой файла, снижая риск конфликтов в многопроцессной среде.

Пример 5. Обход ограничений кодировки: использование OutputStreamWriter вместо FileWriter.

Пример java
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;

try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("utf8.txt"), StandardCharsets.UTF_8))) {
    bw.write("Текст с символами € и эмодзи ????\n");
}
Результат: utf8.txt корректно содержит специфичные символы в UTF-8, в отличие от FileWriter при неподходящей системной кодировке.

джава FileWriter function comments

En
FileWriter A writer for writing character files