OutputStream.close: примеры (JAVA)
OutputStream.close: voidОписание и назначение
Метод OutputStream.close() служит для закрытия потока вывода и освобождения связанных с ним системных ресурсов. После вызова close() дальнейшие операции записи обычно приводят к IOException. Реализация может выполнить дополнительную очистку, например вызвать flush() перед закрытием.
Сигнатура и возвращаемое значение
Сигнатура в классе java.io.OutputStream:
public void close() throws IOException
Метод не возвращает значений (void). При ошибке ввода-вывода выбрасывается IOException. Многие подклассы переопределяют поведение.
Когда используется
- После завершения записи в файл, сокет или другой носитель данных.
- Для освобождения системных дескрипторов и буферов.
- В сочетании с try-with-resources для автоматического закрытия.
Особенности реализации
- В стандартной реализации
FilterOutputStream.close()сначала вызываетflush(), затем закрывает вложенный поток. - Некоторые реализации могут игнорировать повторные вызовы
close()(идемпотентность), другие могут выбрасывать исключение при операциях после закрытия. - Класс
OutputStreamреализует интерфейсCloseable, что позволяет использовать try-with-resources (Java 7+).
Короткие примеры использования
1. Ручное закрытие в try-finally
FileOutputStream fos = null;
try {
fos = new FileOutputStream("out.txt");
fos.write("Привет\n".getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try { fos.close(); } catch (IOException ignored) {}
}
}
Код создаст файл out.txt с содержимым "Привет". При ошибке будет напечатан стек трейс, затем поток закроется.
2. try-with-resources (рекомендуется)
try (FileOutputStream fos = new FileOutputStream("out2.txt")) {
fos.write("Тест\n".getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
Файл out2.txt будет содержать "Тест". Поток закроется автоматически, исключения закрытия станут подавленными и доступны через Throwable.getSuppressed().
3. Закрытие обёртки и влияние на внутренний поток
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("out3.txt"))) {
bos.write(new byte[]{1,2,3});
} catch (IOException e) {
e.printStackTrace();
}
BufferedOutputStream.flush() будет вызван перед закрытием, данные попадут в файл out3.txt.
Похожие методы и их особенности в Java
flush()- очищает буферы, не закрывая поток. Используется когда нужно гарантировать запись, но продолжить работу с потоком.Closeable.close()иAutoCloseable.close()- интерфейсы, которые реализуют потоки; различие в сигнатурах (AutoCloseable.close() может бросать Exception, Closeable.close() бросает IOException).Socket.shutdownOutput()- для сокетов сигнализирует о завершении отправки данных, но сам сокет остаётся открыным для чтения.Channel.close()(NIO) - закрывает канал; при работе с FileChannel предпочтительнее использовать NIO-методы.
При необходимости только сброса буферов лучше применять flush(). Для автоматического управления ресурсами предпочтительнее try-with-resources с Closeable.
Аналоги в других языках и отличия
- PHP
$fp = fopen('out.txt', 'w');
fwrite($fp, "Пример\n");
fclose($fp);
fclose закрывает ресурс; в PHP ошибки закрытия обычно не выбрасываются как исключения.
const fs = require('fs');
const stream = fs.createWriteStream('out.txt');
stream.write('Hi\n');
stream.end(); // закрывает и вызывает finish
end() завершает запись и закрывает поток; ошибки передаются через событие 'error'.
with open('out.txt', 'wb') as f:
f.write(b'Привет\n')
Контекстный менеджер автоматически вызывает close(); исключения закрытия могут подавляться аналогично Java.
using (var fs = new FileStream("out.txt", FileMode.Create)) {
var data = System.Text.Encoding.UTF8.GetBytes("Привет\n");
fs.Write(data, 0, data.Length);
}
using гарантирует вызов Dispose(), который выполняет закрытие потока. Исключения различаются: IOException и другие типы.
f, _ := os.Create("out.txt")
defer f.Close()
f.Write([]byte("Привет\n"))
Close возвращает ошибку, которую рекомендуется проверять; defer обеспечивает вызов Close.
local f = io.open('out.txt', 'w')
f:write('Привет\n')
f:close()
close возвращает true/false и сообщение об ошибке; модель отличается от исключений Java.
val fos = FileOutputStream("out.txt")
fos.use { it.write("Привет\n".toByteArray()) }
use является обёрткой над try-with-resources, автоматически закрывает поток.
Главное отличие - модель ошибок и механизм автоматического закрытия: Java использует исключения и try-with-resources, многие языки применяют контекстные менеджеры или явные возвращаемые коды.
Изменения в поведении в новых версиях Java
- Сама сигнатура
OutputStream.close()практически не менялась в последних релизах; метод остаётся наследуемым и бросаетIOException. - Ключевое изменение - введение try-with-resources в Java 7 и интерфейса
AutoCloseable, что упростило корректное закрытие потоков.Closeableсовместим с AutoCloseable, и это повлияло на паттерны использования. - В последних релизах JDK улучшалось поведение средств диагностики (jcmd, утилиты) по утечкам дескрипторов, но сам метод остаётся обратнопсовместимым.
Продвинутые и необычные примеры
1. Обработка подавленных исключений при try-with-resources
class BadStream extends OutputStream {
private final boolean throwOnClose;
BadStream(boolean t) { this.throwOnClose = t; }
public void write(int b) {}
public void close() throws IOException {
if (throwOnClose) throw new IOException("close failed");
}
}
try (BadStream s = new BadStream(true)) {
throw new IOException("write failed");
} catch (IOException e) {
System.out.println("Caught: " + e.getMessage());
for (Throwable t : e.getSuppressed()) System.out.println("Suppressed: " + t.getMessage());
}
Вывод: Caught: write failed Suppressed: close failed Появляется подавленное исключение от close, доступное через getSuppressed().
2. Создание потока, который не закрывает внутренний ресурс (CloseShield)
class NoCloseOutputStream extends FilterOutputStream {
NoCloseOutputStream(OutputStream out) { super(out); }
public void close() throws IOException { // переопределено: ничего не закрывать
out.flush(); // можно только сбросить буфер
}
}
FileOutputStream fos = new FileOutputStream("shared.txt");
try (NoCloseOutputStream nc = new NoCloseOutputStream(fos)) {
nc.write("A\n".getBytes());
}
fos.write("B\n".getBytes());
fos.close();
Используется когда один ресурс должен обслуживать несколько обёрток, и закрытие одной из них не должно закрывать общий ресурс.
3. Закрытие socket.getOutputStream() vs socket.close()
Socket socket = new Socket(host, port);
OutputStream os = socket.getOutputStream();
os.write(...);
os.close(); // закрывает только поток вывода на стороне сокета
// для полного освобождения TCP-соединения рекомендуется socket.close()
shutdownOutput/signals могут отличаться: закрытие только OutputStream отправит FIN для отправки, но входящий поток остаётся слушаемым до socket.close().
4. Переопределение close в собственном потоке с учётом конкурентного доступа
class SafeOutputStream extends OutputStream {
private volatile boolean closed = false;
public synchronized void write(int b) throws IOException {
if (closed) throw new IOException("closed");
// запись
}
public synchronized void close() throws IOException {
if (closed) return;
// очистка ресурсов
closed = true;
}
}
Используется для предотвращения гонок при одновременных вызовах write/close из разных потоков.
5. Применение Closeable при работе с NIO каналом
try (WritableByteChannel ch = Files.newByteChannel(Paths.get("out.bin"), StandardOpenOption.CREATE)) {
ch.write(ByteBuffer.wrap(new byte[]{1,2,3}));
} catch (IOException e) {
e.printStackTrace();
}
Channel закроется автоматически; предпочтительно для высокопроизводительных операций ввода-вывода.