FileOutputStream: примеры (JAVA)
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
- Files.newOutputStream / Files.write (NIO.2)
- RandomAccessFile
- FileChannel и ByteBuffer
Добавляет буферирование записи для повышения скорости при множественных небольших операциях. Предпочтительнее при частых мелких записах.
Высокоуровневый класс для записи текстовых данных (символы, с указанием кодировки через комбинацию с OutputStreamWriter). Удобнее для текстовых файлов, но не подходит для бинарных данных.
Предоставляет удобные статические методы из java.nio.file.Files с поддержкой опций (CREATE, APPEND, TRUNCATE_EXISTING). Удобен для атомарных операций и сочетания с Path.
Подходит для произвольного доступа к файлу (чтение/запись в произвольных позициях). Предпочтителен при необходимости записи в середину файла.
Предпочтительны для высокопроизводительных операций и работы с блокировками, позиционированием, transfer и memory-mapped файлами.
Аналоги в других языках и отличия
- PHP (fopen/fwrite)
<?
$fp = fopen('out.txt', 'wb');
fwrite($fp, "Привет\n");
fclose($fp);
?>
Содержимое out.txt: Привет
PHP использует дескриптор ресурса; режимы 'wb' и 'ab' соответствуют перезаписи и добавлению.
const fs = require('fs');
fs.writeFileSync('out.txt', 'Привет\n');
// или поток
const stream = fs.createWriteStream('out.txt', { flags: 'a' });
stream.write('Добавлено\n');
stream.end();
Файл содержит текст; синхронный метод блокирует выполнение, потоки работают асинхронно.
with open('out.txt', 'wb') as f:
f.write('Привет\n'.encode('utf-8'))
Содержимое файла: Привет
Python предоставляет режимы 'wb' и 'ab' и контекстный менеджер, аналог try-with-resources.
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 строки.
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.
import java.io.FileOutputStream
fun main() {
FileOutputStream("out.txt").use { it.write("Привет\n".toByteArray()) }
}
Код практически идентичен Java, но использован синтаксис Kotlin и .use для автоматического закрытия.
Прямой аналог отсутствует: запись файлов обычно выполняется на стороне приложения или через 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 зависит от среды
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)
- Try-with-resources
- NIO FileChannel
Появление пакета java.nio.file и класса Files с удобными методами для записи и управления файлами. Примеры: Files.write, Files.newOutputStream.
Добавление в Java 7 конструкции try-with-resources упростило управление потоками и гарантировало корректное закрытие.
Развитие NIO предоставило мощные возможности через FileChannel, доступные также из FileOutputStream через getChannel().
В новых версиях рекомендуется рассматривать NIO.2 и Files API для большинства задач по работе с файлами, оставляя FileOutputStream для совместимости и специфичных случаев низкоуровневой записи.
Расширенные и редкие сценарии использования
1) Принудительная запись данных на диск (fsync)
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 для защиты от конкурентной записи
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 для повышения производительности
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)
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
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()
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)
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 и обёртками предоставляет гибкие возможности для разных задач.