java - outputstreamwriter to outputstream
En Java, cuando llamo a OutputStream.close() ¿siempre necesito llamar a OutputStream.flush() antes? (5)
Si acabo de llamar a close()
en un flujo de salida, la salida está garantizada, o ¿necesito que llame a flush()
siempre?
Aquí hay tantas respuestas y comentarios peligrosos. Sigue leyendo por qué usé la palabra peligroso .
Lo primero es lo primero. Mira esto.
Descubrirá que no existe una declaración única que indique que close()
llame a flush()
. Solucionarme si me perdí alguno.
Utilice flush()
siempre que necesite o necesite garantizar que los datos almacenados en búfer se hayan descargado al menos en el nivel del sistema operativo.
flush()
tiene su propio (s) propósito (s).
// client
// sends exactly 234 bytes
// and returns exactly 124 bytes from the server
static byte[] sendAndReceive(final OutputStream output,
final InputStream input)
throws IOException {
final byte[] request = new byte[234];
output.write(request);
// output.flush(); // @@? is this required or not?
final byte[] response = new byte[124];
new DataInputStream(input).readFully(response);
return response;
}
// server
// recieve exactly 234 bytes from the client
// sends exactly 124 bytes
static void receiveAndSend(final InputStream input,
final OutputStream output)
throws IOException {
final byte[] request = new byte[234];
new DataInputStream(input).readFully(request);
final byte[] response = new byte[124];
output.write(response);
// output.flush(); // @@? is this required or not?
}
Las cosas podrían haber cambiado, pero lo experimenté hace una década. El código fuente anterior (cliente) funcionó con Windows XP y falló con Windows 2000 Server para un mismo punto final (servidor).
Y (usted) no (tiene que) confiar en ningún comportamiento específico de la implementación de close()
.
static void writeFile(File file, byte[] bytes) throws IOException {
try (OutputStream out = new FileOutputStream(bytes)) {
out.write(bytes);
out.flush(); // who cares what FileInputStream#close does?
}
}
Tenga en cuenta también que el flush()
no significa escribir / enviar sus datos al disco físico o punto final remoto. En su mayoría, simplemente vacía los datos almacenados en la JVM en el sistema operativo subyacente.
errata
Writer#close()
explícitamente dice que
cierra la corriente, enjuagándola primero.
Pero no significa que todas las subclases mantienen este contrato raíz. Vea PrintWriter#close()
que (sin flush()
) cierra la out
interna ( Writer
) que, de nuevo, depende de la out
de close()
out
.
Close () siempre se vacía, por lo que no es necesario llamar.
EDITAR: Esta respuesta se basa en el sentido común y en todo el outputtream que encontré. ¿Quién va a implementar un close () para una transmisión en búfer sin tener que descargar el búfer primero? No hay problema para llamar a color justo antes de cerrar (). Sin embargo, hay consecuencias si flush () se llama en exceso. Puede vencer debajo del mecanismo de almacenamiento en búfer.
Los flujos representan recursos que siempre debe limpiar explícitamente, llamando al método de cierre. Algunas clases de java.io (aparentemente solo las clases de salida) incluyen un método de descarga . Cuando se invoca un método de cierre en una clase de este tipo, automáticamente se realiza una descarga. No es necesario llamar explícitamente a flush antes de llamar a close .
Si bien close
debería llamar a flush
, es un poco más complicado que eso ...
En primer lugar, los decoradores (como BufferedOutputStream
) son comunes en Java. La construcción del decorador puede fallar, por lo que debe close
la secuencia "en bruto" en un bloque close
cuyo try
incluye al decorador. En el caso de una excepción, generalmente no necesita close
el decorador (excepto, por ejemplo, para decoradores de compresión mal implementados). Normalmente necesita flush
el decorador en el caso de no excepción. Por lo tanto:
final RawOutputStream rawOut = new RawOutputStream(rawThing);
try {
final DecoratedOutputStream out = new DecoratedOutputStream(rawOut);
// ... stuff with out within ...
out.flush();
} finally {
rawOut.close();
}
Para colmo, los métodos de close
decorador a menudo se implementan incorrectamente. Eso incluye algunos en java.io
hasta hace poco.
Por supuesto, es probable que desee utilizar el idioma Execute Around para mantenerlo en DRY (ish).
Si desea que la secuencia se vacíe, entonces sí , llame a flush()
antes de llamar a close()
.
A pesar de todas las demás respuestas en sentido contrario (pero como se señala correctamente en algunos comentarios), la implementación predeterminada de java.io.OutputStream::close()
no llama a flush()
. De hecho, no hace nada. Si tiene una distribución de fuente, puede verificarla fácilmente por sí mismo, de lo contrario solo confíe en el javadoc oficial , citado aquí:
El contrato general de cierre es que cierra el flujo de salida. Una secuencia cerrada no puede realizar operaciones de salida y no se puede volver a abrir.
El método cercano de OutputStream no hace nada.
Independientemente de si close()
lava o no, el enfoque más seguro debería ser enjuagarlo manualmente. Si se enrojece de nuevo, ¿a quién le importa?
La respuesta de "Tom Hawtin - tackline" tiene detalles adicionales sobre el cierre seguro de las transmisiones (pero realmente no responde claramente la pregunta original = P).