← Назад к вопросам

Какие знаешь базовые реализации OutputStream?

1.3 Junior🔥 121 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Базовые реализации OutputStream

Иерархия OutputStream

java.io.OutputStream (абстрактный класс)
├─ ByteArrayOutputStream
├─ FileOutputStream
├─ PipedOutputStream
├─ ObjectOutputStream
├─ FilterOutputStream
│  ├─ BufferedOutputStream
│  ├─ DataOutputStream
│  ├─ PrintStream
│  └─ CheckedOutputStream
└─ java.net.Socket.getOutputStream()

1. ByteArrayOutputStream

Записывает данные в буфер памяти (byte array).

// Использование
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("Hello".getBytes());
baos.write(' ');
baos.write("World".getBytes());

byte[] data = baos.toByteArray(); // [H, e, l, l, o, ...]
String result = baos.toString();   // "Hello World"

// Практический пример: сериализация
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(myObject);
byte[] serialized = baos.toByteArray();

Когда использовать:

  • Временное хранилище данных в памяти
  • Перед отправкой по сети (нужно знать размер)
  • Тестирование
  • Сериализация в памяти

2. FileOutputStream

Записывает данные в файл на диск.

// Использование
FileOutputStream fos = new FileOutputStream("output.txt");
fos.write("Hello, File!".getBytes());
fos.close(); // Обязательно закрыть!

// С параметром append (добавление)
FileOutputStream fos = new FileOutputStream("log.txt", true);
fos.write("New log line\n".getBytes());
fos.close();

// С try-with-resources (Java 7+)
try (FileOutputStream fos = new FileOutputStream("output.txt")) {
    fos.write("Automatic close".getBytes());
} // Автоматически закроется

// Практический пример
FileOutputStream fos = new FileOutputStream("data.bin");
fos.write(255);     // Один байт
fos.write(new byte[]{1, 2, 3}); // Массив байт
fos.close();

Когда использовать:

  • Запись в файлы
  • Логирование
  • Сохранение данных на диск
  • Низкоуровневая I/O операция

3. BufferedOutputStream

Оборачивает другой OutputStream и добавляет буферизацию.

// Использование
FileOutputStream fos = new FileOutputStream("output.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos, 8192); // 8KB буфер
bos.write("Buffered data".getBytes());
bos.flush(); // Принудительно записать буфер на диск
bos.close();

// Отличие без буфера
FileOutputStream fos = new FileOutputStream("output.txt");
for (int i = 0; i < 1000000; i++) {
    fos.write(("Line " + i + "\n").getBytes());
    // 1 миллион системных вызовов к диску (медленно!)
}

// С буфером
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.txt"));
for (int i = 0; i < 1000000; i++) {
    bos.write(("Line " + i + "\n").getBytes());
    // Несколько системных вызовов (быстро!)
}
bos.close();

Когда использовать:

  • Множественные операции записи
  • Требуется производительность
  • Оборачивание других потоков

4. ObjectOutputStream

Сериализует объекты в двоичный формат.

// Использование
public class User implements Serializable {
    private String name;
    private int age;
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// Запись объекта
User user = new User("John", 30);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.dat"));
oos.writeObject(user);
oos.close();

// Чтение обратно
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.dat"));
User loadedUser = (User) ois.readObject();
ois.close();

Когда использовать:

  • Сохранение объектов Java в файл
  • RMI (Remote Method Invocation)
  • Кэширование сложных структур

5. DataOutputStream

Оборачивает другой поток и добавляет методы для записи примитивных типов.

// Использование
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"));
dos.writeInt(42);
dos.writeDouble(3.14);
dos.writeUTF("Hello"); // UTF-8 строка с длиной
dos.close();

// Чтение
DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"));
int num = dis.readInt();       // 42
double pi = dis.readDouble();  // 3.14
String text = dis.readUTF();   // "Hello"
dis.close();

// Практический пример: бинарный протокол
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.writeByte(1);              // Command type
dos.writeShort(100);           // Data size
dos.writeUTF("user data");     // Payload
dos.flush();

Когда использовать:

  • Бинарные протоколы
  • Сохранение примитивных типов
  • Network communication

6. PrintStream

Удобный поток для вывода текста (System.out и System.err).

// System.out это PrintStream
System.out.println("Hello");
System.out.print("No newline");

// Создание собственного PrintStream
PrintStream ps = new PrintStream(new FileOutputStream("output.txt"));
ps.println("Line 1");
ps.println("Line 2");
ps.printf("Number: %d\n", 42);
ps.close();

// С автоматическим flush
PrintStream ps = new PrintStream(new FileOutputStream("output.txt"), true);
ps.println("Auto-flushed"); // Автоматически flush

// Практический пример: перенаправление System.out
PrintStream fileOut = new PrintStream(new FileOutputStream("app.log"));
System.setOut(fileOut);
System.out.println("This goes to file");

Когда использовать:

  • Логирование текста Удобный человекочитаемый вывод
  • System.out/System.err

7. PipedOutputStream

Соединяет два потока в pipe (конвейер).

// Использование
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);

// Поток 1: пишет в pipe
Thread writerThread = new Thread(() -> {
    try {
        pos.write("Hello from thread 1".getBytes());
        pos.close();
    } catch (IOException e) {}
});

// Поток 2: читает из pipe
Thread readerThread = new Thread(() -> {
    try {
        byte[] buffer = new byte[1024];
        int read = pis.read(buffer);
        System.out.println(new String(buffer, 0, read));
    } catch (IOException e) {}
});

writerThread.start();
readerThread.start();
writerThread.join();
readerThread.join();

Когда использовать:

  • Многопоточная коммуникация
  • Конвейеры между потоками
  • Тестирование

Сравнение потоков

КлассНазначениеБуферизацияПримитивыОбъекты
FileOutputStreamФайлНетДаНет
ByteArrayOutputStreamПамятьВстроеннаяДаНет
BufferedOutputStreamБуферизацияДаДаНет
ObjectOutputStreamСериализацияНетДаДа
DataOutputStreamПримитивыНетДаНет
PrintStreamТекстДаДаНет
PipedOutputStreamPipeВстроеннаяДаНет

Лучшие практики

1. Всегда закрывай потоки

// ❌ Плохо — может утечка ресурсов
FileOutputStream fos = new FileOutputStream("file.txt");
fos.write("data".getBytes());
// Забыли закрыть!

// ✅ Хорошо — try-with-resources
try (FileOutputStream fos = new FileOutputStream("file.txt")) {
    fos.write("data".getBytes());
} // Автоматически закроется

2. Используй BufferedOutputStream для множественных операций

// ❌ Медленно
FileOutputStream fos = new FileOutputStream("file.txt");
for (int i = 0; i < 1000000; i++) {
    fos.write(data);
}

// ✅ Быстро
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("file.txt"));
for (int i = 0; i < 1000000; i++) {
    bos.write(data);
}
bos.close();

3. Вызывай flush() перед close()

FileOutputStream fos = new FileOutputStream("file.txt");
fos.write("data".getBytes());
fos.flush(); // Убедиться, что данные написаны
fos.close();

Заключение

Основные реализации OutputStream — это важная часть Java I/O API:

  • FileOutputStream — основной класс для записи в файлы
  • ByteArrayOutputStream — буфер в памяти
  • BufferedOutputStream — буферизация для производительности
  • ObjectOutputStream — сериализация объектов
  • DataOutputStream — примитивные типы
  • PrintStream — удобный текстовый вывод
  • PipedOutputStream — межпоточная коммуникация

Выбор правильного потока зависит от задачи: где писать, что писать и нужна ли буферизация.

Какие знаешь базовые реализации OutputStream? | PrepBro