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

FileOutputStream в Java: применение и примеры
Раздел: Потоки ввода-вывода (Streams) байтовые
FileOutputStream(File file, String name, boolean append)

Описание класса FileOutputStream

Класс FileOutputStream из пакета java.io предоставляет поток для записи последовательности байтов в файл или в открытый дескриптор файла. Применение характерно для записи бинарных данных и байтовых представлений текстовой информации.

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

  • FileOutputStream(String name) - открывает или создаёт файл с указанным именем для записи. Если файл существует, его содержимое будет перезаписано (truncate). Возможные исключения: FileNotFoundException (например, если путь не существует или права доступа запрещены).
  • FileOutputStream(String name, boolean append) - как предыдущий, но при append == true новые байты добавляются в конец файла.
  • FileOutputStream(File file) - аналогично конструктору с именем, параметр типа java.io.File.
  • FileOutputStream(File file, boolean append) - вариант с флагом добавления.
  • FileOutputStream(FileDescriptor fdObj) - оборачивает существующий файловый дескриптор (FileDescriptor), например, для стандартных потоков (FileDescriptor.out).

Основные методы (унаследованные из OutputStream и специфичные)

  • void write(int b) - запись одного байта (младшие 8 бит аргумента записываются).
  • void write(byte[] b) - запись всего массива байтов.
  • void write(byte[] b, int off, int len) - запись части массива, начиная с индекса off, длиной len.
  • void close() - закрытие потока и освобождение ресурсов; может бросать IOException.
  • FileDescriptor getFD() - получение дескриптора файла; полезно для вызова sync() для принудительной записи на диск.
  • FileChannel getChannel() - получение NIO-канала файла; доступно для расширенных операций (блокировки, позиционирование, transfer и т. п.).

Возвращаемые значения и исключения

Методы записи возвращают void. Конструкторы создают экземпляр или выбрасывают FileNotFoundException. При операциях записи и закрытия могут возникать IOException. При попытке доступа без прав возможен SecurityException.

Когда подходит использование FileOutputStream

  • Запись сырых байтов (бинарные форматы, изображения, архивы).
  • Нужен низкоуровневый контроль над записью и доступ к FileDescriptor или FileChannel.
  • В бюджетных по памяти сценариях, при использовании небольших буферов комбинируется с BufferedOutputStream для повышения производительности.

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

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

import java.io.*;

public class Example1 {
    public static void main(String[] args) throws Exception {
        try (FileOutputStream fos = new FileOutputStream("out1.txt")) {
            byte[] data = "Привет, файл!\n".getBytes("UTF-8");
            fos.write(data);
        }
        System.out.println("Запись завершена");
    }
}
Содержимое файла out1.txt:
Привет, файл!

Вывод программы:
Запись завершена

2) Добавление в конец файла (append)

import java.io.*;

public class Example2 {
    public static void main(String[] args) throws Exception {
        try (FileOutputStream fos = new FileOutputStream("out1.txt", true)) {
            fos.write("Добавлено\n".getBytes("UTF-8"));
        }
    }
}
Содержимое файла out1.txt после выполнения:
Привет, файл!
Добавлено

3) Запись части массива байтов

import java.io.*;

public class Example3 {
    public static void main(String[] args) throws Exception {
        byte[] bytes = new byte[] {65, 66, 67, 68, 69}; // ASCII A..E
        try (FileOutputStream fos = new FileOutputStream("out3.bin")) {
            fos.write(bytes, 1, 3); // запишет B, C, D
        }
    }
}
Содержимое out3.bin (в ASCII): B C D
(файл длиной 3 байта: 66 67 68)

4) Использование FileDescriptor для стандартного вывода

import java.io.*;

public class Example4 {
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream(FileDescriptor.out);
        fos.write("Вывод через FileOutputStream\n".getBytes("UTF-8"));
        fos.flush(); // не закрывать, чтобы не закрыть System.out
    }
}
Вывод программы в консоль:
Вывод через FileOutputStream

Похожие классы и выбор между ними

  • BufferedOutputStream
  • Добавляет буферирование записи для повышения скорости при множественных небольших операциях. Предпочтительнее при частых мелких записах.

  • FileWriter
  • Высокоуровневый класс для записи текстовых данных (символы, с указанием кодировки через комбинацию с OutputStreamWriter). Удобнее для текстовых файлов, но не подходит для бинарных данных.

  • Files.newOutputStream / Files.write (NIO.2)
  • Предоставляет удобные статические методы из java.nio.file.Files с поддержкой опций (CREATE, APPEND, TRUNCATE_EXISTING). Удобен для атомарных операций и сочетания с Path.

  • RandomAccessFile
  • Подходит для произвольного доступа к файлу (чтение/запись в произвольных позициях). Предпочтителен при необходимости записи в середину файла.

  • FileChannel и ByteBuffer
  • Предпочтительны для высокопроизводительных операций и работы с блокировками, позиционированием, transfer и memory-mapped файлами.

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

  • PHP (fopen/fwrite)
  • <?
    $fp = fopen('out.txt', 'wb');
    fwrite($fp, "Привет\n");
    fclose($fp);
    ?>
    Содержимое out.txt:
    Привет

    PHP использует дескриптор ресурса; режимы 'wb' и 'ab' соответствуют перезаписи и добавлению.

  • JavaScript (Node.js, fs)
  • const fs = require('fs');
    fs.writeFileSync('out.txt', 'Привет\n');
    // или поток
    const stream = fs.createWriteStream('out.txt', { flags: 'a' });
    stream.write('Добавлено\n');
    stream.end();
    Файл содержит текст; синхронный метод блокирует выполнение, потоки работают асинхронно.
  • Python (open, write)
  • with open('out.txt', 'wb') as f:
        f.write('Привет\n'.encode('utf-8'))
    Содержимое файла: Привет

    Python предоставляет режимы 'wb' и 'ab' и контекстный менеджер, аналог try-with-resources.

  • C# (FileStream)
  • using System.IO;
    File.WriteAllBytes("out.bin", System.Text.Encoding.UTF8.GetBytes("Привет\n"));
    // или
    using (var fs = new FileStream("out.bin", FileMode.Create)) {
        byte[] data = System.Text.Encoding.UTF8.GetBytes("Привет\n");
        fs.Write(data, 0, data.Length);
    }
    Файл out.bin содержит байты UTF-8 строки.
  • Go (os.OpenFile)
  • package main
    import (
        "os"
    )
    func main() {
        f, _ := os.OpenFile("out.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
        defer f.Close()
        f.Write([]byte("Привет\n"))
    }
    
    Файл содержит текст; параметры OpenFile соответствуют режимам Java.
  • Kotlin
  • import java.io.FileOutputStream
    fun main() {
        FileOutputStream("out.txt").use { it.write("Привет\n".toByteArray()) }
    }
    
    Код практически идентичен Java, но использован синтаксис Kotlin и .use для автоматического закрытия.
  • SQL
  • Прямой аналог отсутствует: запись файлов обычно выполняется на стороне приложения или через BLOB-интерфейсы СУБД (INSERT/UPDATE BLOB). Отличие - управление хранением данных в базе.

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

  • FileNotFoundException
  • Частая причина - попытка открыть файл в директории, которой не существует, или отсутствие прав на создание/запись. Пример:

    import java.io.*;
    public class Err1 {
        public static void main(String[] args) {
            try (FileOutputStream fos = new FileOutputStream("/no/such/dir/out.txt")) {
                fos.write(1);
            } catch (Exception e) {
                System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
            }
        }
    }
    Вывод программы:
    FileNotFoundException: /no/such/dir/out.txt (No such file or directory)
  • IOException при записи
  • Может возникать при полном диске или ошибке оборудования. Пример симулируется перехватом исключения:

    // Пример демонстрационный; реальная IOException зависит от среды
    try (FileOutputStream fos = new FileOutputStream("out.txt")) {
        // при переполнении диска или проблеме здесь может появиться IOException
        fos.write(new byte[0]);
    } catch (IOException e) {
        System.out.println("Ошибка ввода-вывода: " + e.getMessage());
    }
    Вывод при проблеме: Ошибка ввода-вывода: <описание ошибки>
  • Запись в закрытый поток
  • import java.io.*;
    public class Err2 {
        public static void main(String[] args) throws Exception {
            FileOutputStream fos = new FileOutputStream("out.txt");
            fos.close();
            try {
                fos.write(1);
            } catch (IOException e) {
                System.out.println("Exception: " + e.getClass().getSimpleName());
            }
        }
    }
    Вывод программы:
    Exception: IOException
  • Проблемы с кодировкой при записи текстов
  • Прямой вызов getBytes() без указания кодировки может привести к непредсказуемым результатам на разных платформах. Рекомендуется явно указывать Charset (например, UTF-8).

Изменения и эволюция использования

Сам класс FileOutputStream не претерпевал значительных API-изменений в недавних релизах Java. Главные изменения в экосистеме, влияющие на выбор этого класса:

  • Java 7 (NIO.2)
  • Появление пакета java.nio.file и класса Files с удобными методами для записи и управления файлами. Примеры: Files.write, Files.newOutputStream.

  • Try-with-resources
  • Добавление в Java 7 конструкции try-with-resources упростило управление потоками и гарантировало корректное закрытие.

  • NIO FileChannel
  • Развитие NIO предоставило мощные возможности через FileChannel, доступные также из FileOutputStream через getChannel().

В новых версиях рекомендуется рассматривать NIO.2 и Files API для большинства задач по работе с файлами, оставляя FileOutputStream для совместимости и специфичных случаев низкоуровневой записи.

Расширенные и редкие сценарии использования

1) Принудительная запись данных на диск (fsync)

Пример java
import java.io.*;

public class Adv1 {
    public static void main(String[] args) throws Exception {
        try (FileOutputStream fos = new FileOutputStream("out_sync.txt")) {
            fos.write("важные данные\n".getBytes("UTF-8"));
            fos.getFD().sync(); // гарантирует запись на физический носитель
        }
        System.out.println("Синхронизация завершена");
    }
}
Вывод программы:
Синхронизация завершена
Файл out_sync.txt содержит: важные данные

2) Блокировка файла через FileChannel для защиты от конкурентной записи

Пример java
import java.io.*;
import java.nio.channels.FileLock;

public class Adv2 {
    public static void main(String[] args) throws Exception {
        try (FileOutputStream fos = new FileOutputStream("lock.txt", true)) {
            FileLock lock = fos.getChannel().lock();
            try {
                fos.write("Запись с блокировкой\n".getBytes("UTF-8"));
            } finally {
                lock.release();
            }
        }
    }
}
Файл lock.txt содержит дополнительную строку, при этом другие процессы, соблюдающие блокировку, не смогут одновременно модифицировать ту же область.

3) Комбинация BufferedOutputStream для повышения производительности

Пример java
import java.io.*;

public class Adv3 {
    public static void main(String[] args) throws Exception {
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("big.bin"))) {
            byte[] chunk = new byte[8192];
            for (int i = 0; i < 1000; i++) bos.write(chunk);
        }
        System.out.println("Создан большой файл");
    }
}
Вывод программы:
Создан большой файл
Файл big.bin размером ~8МБ

4) Запись с последующей атомарной заменой (tmp + move)

Пример java
import java.io.*;
import java.nio.file.*;

public class Adv4 {
    public static void main(String[] args) throws Exception {
        Path tmp = Files.createTempFile("tmpdata", ".tmp");
        try (FileOutputStream fos = new FileOutputStream(tmp.toFile())) {
            fos.write("новые данные\n".getBytes("UTF-8"));
            fos.getFD().sync();
        }
        Files.move(tmp, Paths.get("target.txt"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
        System.out.println("Атомарная замена выполнена");
    }
}
Вывод программы:
Атомарная замена выполнена
Файл target.txt заменён на новую версию

5) Запись с компрессией через GZIPOutputStream

Пример java
import java.io.*;
import java.util.zip.GZIPOutputStream;

public class Adv5 {
    public static void main(String[] args) throws Exception {
        try (GZIPOutputStream gos = new GZIPOutputStream(new FileOutputStream("data.gz"))) {
            gos.write("сжимаемые данные\n".getBytes("UTF-8"));
        }
    }
}
Результат: файл data.gz содержит сжатые байты; размер меньше, чем у оригинального текста.

6) Использование FileChannel.transferFrom/transferTo через FileOutputStream.getChannel()

Пример java
import java.io.*;
import java.nio.channels.FileChannel;

public class Adv6 {
    public static void main(String[] args) throws Exception {
        try (FileOutputStream dest = new FileOutputStream("copy.bin");
             FileInputStream src = new FileInputStream("out3.bin")) {
            FileChannel srcCh = src.getChannel();
            FileChannel dstCh = dest.getChannel();
            dstCh.transferFrom(srcCh, 0, srcCh.size());
        }
    }
}
Результат: содержимое out3.bin скопировано в copy.bin с использованием каналов, что может быть более эффективно при больших файлах.

7) Запись сериализованного объекта (ObjectOutputStream + FileOutputStream)

Пример java
import java.io.*;

public class Adv7 implements Serializable {
    private String name = "obj";
    public static void main(String[] args) throws Exception {
        Adv7 a = new Adv7();
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.dat"))) {
            oos.writeObject(a);
        }
    }
}
Файл obj.dat содержит сериализованное представление объекта; чтение через ObjectInputStream восстанавливает состояние.

Комментарии

Каждый пример демонстрирует реальные приёмы: форсирование записи на диск, блокировки, производительность и атомарность замен. Комбинация FileOutputStream с NIO и обёртками предоставляет гибкие возможности для разных задач.

джава FileOutputStream function comments

En
FileOutputStream An output stream for writing data to a file