Los programas muy a menudo requieren escribir datos en un archivo o en otro lugar de forma rápida. Esto plantea preguntas: ¿Cómo lo debemos hacer? ¿Qué clase debemos elegir? Hoy conoceremos a un candidato adecuado para este papel: la clase BufferedWriter.

¿Por qué necesitamos BufferedWriter?

BufferedWriter es una clase que escribe caracteres en búfer a un flujo. Permite reducir el número de veces que se accede a los medios físicos. Es decir, en lugar de escribir un solo carácter cada vez, escribe datos en un búfer y luego escribe todos los caracteres en los medios a la vez.

Esto aumenta considerablemente la velocidad de escritura. El tamaño de búfer predeterminado es de 8192 caracteres, pero esto se puede cambiar especificando un nuevo tamaño en el constructor:

BufferedWriter(Writer in, int sz)

Aquí, el primer argumento del constructor es un flujo que recibirá los datos que escribimos. Y resulta que sz es el tamaño del nuevo búfer.

Java también tiene la clase BufferedReader: se utiliza para leer datos en búfer.

¿Qué es exactamente un búfer? Tomemos un ejemplo de la vida real. Un búfer es como una canasta o carrito de compras en un supermercado. En lugar de caminar hacia la caja registradora con un solo artículo, pagar por él, ponerlo en el maletero del automóvil y luego volver por otro artículo, podemos tomar un carrito de compras, poner todo lo que queremos en él y luego pagar en la caja. Así es exactamente como funciona un búfer: recopila datos y luego toma todo y lo escribe, en lugar de escribir cada fragmento por separado.

Constructores y métodos de la clase BufferedWriter

Ahora veamos más de cerca la clase BufferedWriter. Hay dos constructores para crear un objeto:

public BufferedWriter(Writer out)
public BufferedWriter(Writer out, int sz)

En ambos constructores, out es el flujo donde se escribirá la información, y sz, como se mencionó anteriormente, es el tamaño del buffer.

La clase BufferedWriter también tiene varios métodos. Hoy analizaremos algunos de ellos:

write(char[] array) Escribe un array de char en el buffer
write(String s, int off, int len) Escribe parte de una cadena en el buffer
append(char c) Escribe un caracter en el buffer
append(CharSequence csq, int start, int end) Escribe parte de un array en el buffer
newLine() Escribe un separador de línea
flush() Vuelca el stream

Vamos a escribir un programa que escriba un valor en un archivo. Para el parámetro Writer, pasaremos un FileWriter al constructor. Este se utiliza para escribir archivos de texto y tiene varios constructores para inicializar objetos:

FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(FileDescriptor fd)
FileWriter(String fileName)
FileWriter(String fileName, boolean append)

Para nuestro ejemplo, usaremos un constructor que tome un nombre de archivo:

try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"))){

	String message = "Hello, Amigo! This is a very important message!";
	bufferedWriter.write(message);
	bufferedWritter.flush();
}
catch(IOException ex){
System.out.println(ex.getMessage());
 }

Nuestro código utilizará el método write(String str) para escribir str en el archivo file.txt.

Hay otros métodos para escribir:

  • write(char[] array) — esta variante acepta y escribe un array de caracteres (char);

  • write(String s, int off, int len) — esta variante toma una cadena de texto s; un desplazamiento off, que es el índice del carácter desde el cual comenzar a escribir; y len, que es la longitud de la cadena (subcadena) a escribir.

try(BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"))){
	String message = "Hello, Amigo! This is a very important message!";
	bufferedWriter.write(message, 0, 11);
 	bufferedWriter.flush();

} catch(IOException ex) {
System.out.println(ex.getMessage());
}

Este código escribirá "Hello, Amigo!" en la primera línea del archivo y "This is a very important message!" en la segunda. Esto se debe a que utilizamos el método newLine() para agregar una nueva línea entre las dos partes del mensaje. La salida en el archivo sería la siguiente:

Nuestro código también tiene un bloque try-with resources:

try(BufferedWriter bufferedWritter = new BufferedWriter(new FileWriter("file.txt")))

Esto significa que el método close() se llama automáticamente en nuestro objeto bufferedWriter, porque implementa la interfaz AutoCloseable.

El método flush() en el código se usa para vaciar el flujo de salida, forzando la escritura de todos los bytes almacenados en búfer. La escritura puede no ocurrir sin esta llamada, ya que es la que indica que el búfer debe vaciarse y que los bytes almacenados en búfer deben escribirse.

La clase BufferedWriter también tiene un método newLine() que agrega una nueva línea a nuestro mensaje:

try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"))) {
        String message = "Hello, Amigo! This is a very important message!";
        bufferedWriter.write(message, 0, 13);
        bufferedWriter.newLine();
        bufferedWriter.write(message, 15, 33);
    } catch (IOException ex) {
        System.out.println(ex.getMessage());
    }

En el archivo obtenemos:

Hola, Amigo
Este mensaje es muy importante!

La firma del método append() luce de la siguiente manera:

public Writer append(CharSequence csq, int start, int end)

Se utiliza para agregar csq. Aquí, start es el índice del primer carácter, y end es el índice del último carácter de la cadena (o subcadena) que se va a insertar. El carácter con índice end no se inserta.

try (BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"))) {
    String message = "Hello, Amigo! This is a very important message!";
    bufferedWriter.append(message, 0, 7);
    bufferedWriter.flush();
} catch (IOException ex) {
    System.out.println(ex.getMessage());
}

Este código te dará:

Hello,

Es decir, con el método append, especificas qué parte de la cadena se agregará al búfer.

Al examinar más de cerca la diferencia entre los métodos write() y append(), primero vemos que ambos hacen lo mismo en principio, es decir, escriben valores.

Sin embargo, la diferencia es que el método append es más nuevo y toma una CharSequence como argumento, y como String implementa CharSequence, podemos pasar Strings y StringBuilders, y StringBuffers al método append. Pero el método write() solo aceptará un String.

¡Eso es todo por ahora! Hoy nos familiarizamos con los búferes, cómo realizar la escritura en búfer en un archivo, así como los métodos que puedes usar para hacerlo.