Cuando trabajamos con flujos de salida en Java, una de las grandes ventajas es la posibilidad de encadenar varias clases envolventes para optimizar y controlar mejor cómo escribimos datos. Podemos, por ejemplo, combinar un FileOutputStream con un BufferedOutputStream y un ObjectOutputStream para escribir cadenas en un archivo de forma eficiente y estructurada.
Imaginemos que queremos guardar repetidamente una cadena en un archivo. Para ello, podemos crear una función que abra un FileOutputStream apuntando al archivo destino, luego lo envuelva en un BufferedOutputStream para mejorar el rendimiento mediante el almacenamiento en búfer, y finalmente utilice un ObjectOutputStream para escribir objetos, en este caso cadenas, de forma sencilla y segura.
El método clave para escribir cadenas en el ObjectOutputStream es writeUTF, que almacena la cadena en un formato que puede ser leído posteriormente con readUTF. Si repetimos esta operación varias veces, por ejemplo 256 veces, estaremos escribiendo muchas cadenas en el archivo.
Un detalle importante es el uso de flush. Cada tipo de OutputStream tiene su propia política para vaciar los datos almacenados en búfer hacia el destino final. Por eso, aunque no siempre sea estrictamente necesario, es buena práctica llamar a flush en el ObjectOutputStream para asegurarnos de que todos los datos pendientes se escriban efectivamente en el archivo. Esto evita que queden datos suspendidos en memoria que no se hayan volcado aún.
Para ilustrar esto, el código podría ser algo así:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class EscrituraCadenas {
public static void escribirCadenas(String archivo) throws IOException {
try (FileOutputStream fos = new FileOutputStream(archivo);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
for (int i = 0; i < 256; i++) {
oos.writeUTF("cadena\n");
}
oos.flush();
}
}
public static void main(String[] args) throws IOException {
escribirCadenas("cadenas.bin");
}
}
Al ejecutar este código, se genera un archivo binario que contiene las cadenas escritas. Si intentamos abrirlo con un editor de texto común, veremos que hay datos binarios mezclados con las cadenas, ya que el formato de ObjectOutputStream incluye información adicional para manejar objetos. Sin embargo, las cadenas están ahí, reconocibles entre esos datos.
Lo interesante es que no hay límite en la cantidad de capas envolventes que podemos usar. Podemos meter un BufferedOutputStream dentro de otro, o combinar varias clases envolventes según nuestras necesidades. Esto nos da mucha flexibilidad para adaptar la escritura de datos a diferentes escenarios, optimizando rendimiento y funcionalidad.
En definitiva, encadenar OutputStream es una técnica poderosa para manejar la escritura en archivos, y el uso adecuado de métodos como writeUTF y flush nos ayuda a controlar con precisión cómo y cuándo se escriben los datos.