← Назад к вопросам
Какие знаешь базовые реализации 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 | Текст | Да | Да | Нет |
| PipedOutputStream | Pipe | Встроенная | Да | Нет |
Лучшие практики
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 — межпоточная коммуникация
Выбор правильного потока зависит от задачи: где писать, что писать и нужна ли буферизация.