Saltar a contenido

Ficheros de caracteres

alt text

Las clases Java FileWriter y FileReader se utilizan para escribir y leer datos de archivos de texto (son clases de flujo de caracteres, character stream). Se recomienda no utilizar las clases FileInputStream y FileOutputStream si vamos a leer o escribir información de texto.

Extensión Tipo de fichero
.txt Fichero de texto plano
.xml Fichero XML
.json Fichero de intercambio de información
.props Fichero de propiedades
.conf Fichero de configuración
.sql Script SQL
.srt Fichero de subtítulo

Escritura de caracteres

La clase Java FileWriter del paquete java.io se utiliza para escribir datos en forma de caracteres en un archivo.

  • Esta clase hereda de la clase OutputStream.
  • Los constructores de esta clase asumen que la codificación de caracteres predeterminada y el tamaño de búfer de bytes predeterminado son aceptables.
  • FileWriter está diseñado para escribir secuencias de caracteres. Si queremos escribir flujos de bytes sin procesar, tendríamos que usar la clase FileOutputStream.

Los métodos principales

Método Descripción
void write(int caracter) escribe un carácter en el archivo
void write(String cadena) escribe una cadena en el archivo
void newline() escribe un salto de línea en el fichero. Se debe evitar el uso explícito del carácter \n para insertar saltos de línea, ya que su codificación es distinta según la plataforma utilizada.
void flush() vacía el buffer de salida, escribiendo en el fichero los caracteres pendientes.
void close() cierra el flujo de salida, vaciando el buffer y liberando el recurso correspondiente.

Cuando trabajamos con flujos es necesario cerrarlo para evitar perdida de recursos, incluso aunque se produzca un error, por lo que normalmente se realiza en el el apartado finally del try/cath.

Warning

Siempre hay que cerrar el flujo para asegurarse de liberar todos los recursos asociados a él y que el sistema operativo no consuma recursos.

La excepción IOException se lanza si el stream se ha cerrado y el flujo de salida contenido no admite la escritura después del cierre, o se produce otro error de I/O.

try-with-resources

La declaración try-with-resource es una característica introducida en Java 7 que facilita la gestión de recursos que deben cerrarse explícitamente, como flujos de archivos o conexiones a bases de datos. Permite que los recursos sean automáticamente cerrados una vez que el bloque try termina, incluso si ocurre una excepción. Esto simplifica el código y reduce la posibilidad de fugas de recursos.

public static void main(String[] args) {
    try(DataOutputStream fos = new DataOutputStream(new FileOutputStream("datos.dat"))) {

        fos.writeInt(0);
        fos.writeInt(-34);

    } catch (FileNotFoundException e) { //todas pueden derivar de IOException
        System.out.println(e.getMessage());
    } catch (IOException e) {
        System.out.println(e.getMessage());
    }
}
Pero podemos seguir usando la versión con finally

Vamos a ver un ejemplo para flujo de caracteres

/** 
* Escribe texto en un fichero llamado "output.txt"
* utilizando BufferedWriter y try-with-resources.
*
* El fichero se crea automáticamente si no existe.
* Si existe, se sobrescribe.
*/
public static void main(String[] args) {

    // try-with-resources:
    // BufferedWriter se cerrará automáticamente al finalizar el bloque
    try (BufferedWriter fw =
                new BufferedWriter(        // Añade buffer (mejora rendimiento)
                        new FileWriter("output.txt"))) { // Conexión al fichero

        // Escribimos una línea de texto
        fw.write("Esto es un ejemplo");

        // Insertamos salto de línea (equivalente a \n pero portable)
        fw.newLine();

        // Escribimos segunda línea
        fw.write("Segunda linea");

        // No es necesario llamar a close()
        // Se cerrará automáticamente

    } catch (IOException e) {

        // Captura errores de entrada/salida
        System.out.println("Error E/S: " + e);
    }
}
public static void main(String[] args)  {      
        BufferedWriter fw=null;
        try {
            fw =new BufferedWriter(new FileWriter("output.txt"));
            fw.write("Esto es un ejemplo"); 
            //nueva linea
            fw.newLine();
            fw.write("Segunda linea"); 
        } catch(IOException e) {
            System.out.println("Error E/S: " + e);
        }finally{
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
}

Cuando se cierra el stream close() se escribe en el fichero.

En el caso de try/resouce no es necesario llamar a close() ya que lo hace de forma automática.

Si quisiéramos grabar en el fichero en algún momento antes de cerrar, podemos usar el método flush().

fw.write("Esto es un ejemplo");
fw.flush();

Escritura de String como System.out

Podemos utilizar la clase PrintWriter para la escritura de String en el archivo. Proporciona métodos parececidos a System.out

 public static void main(String[] args) {

    try (
        FileWriter fileWriter = new FileWriter("output.txt");
        PrintWriter printWriter = new PrintWriter(fileWriter);
    ) {

        // Datos
        String nombre = "Juan";
        int edad = 30;
        double altura = 1.75;

        // ====== CABECERA ======
        // %-10s → String alineado a la izquierda en 10 espacios
        // %10s  → alineado a la derecha en 10 espacios
        printWriter.printf("%-10s %-10s %-10s\n",
                "Nombre", "Edad", "Altura");

         // Línea separadora
            printWriter.println("--------------------------------");

        // ====== DATOS ======
        printWriter.printf("%-10s %-10d %-10.2f\n",
                nombre, edad, altura);

        System.out.println("Se ha escrito en el archivo exitosamente.");

    } catch (Exception e) {
        e.printStackTrace();
    }
}

Lectura de datos

Carácter a carácter: FileReader

FileReader es una clase en el paquete java.io que se usa para leer una secuencia de caracteres de los ficheros. Esta clase se hereda de la clase InputStreamReader.

  • FileReader está diseñada para leer flujos de caracteres. Para leer flujos de bytes sin procesar, usaremos FileInputStream.

Los métodos principales

Método Descripción
readLine() para leer líneas de texto del fichero (String). Este método devuelve null cuando no hay más líneas para leer
read() para leer carácter a carácter. Devuelve un entero que representa el código Unicode del carácter leído. Devuelve -1 si no hay más caracteres.
/**
 * Lee el fichero "output.txt" carácter a carácter
 * y muestra su contenido por pantalla.
 *
 * Utiliza:
 * - FileReader → para leer caracteres (fichero de texto)
 * - try-with-resources → para cerrar automáticamente el flujo
 */
public static void main(String[] args) {

    // Variable donde almacenaremos el carácter leído
    int ch;

    // try-with-resources:
    // FileReader se cerrará automáticamente al salir del bloque
    try (FileReader fr = new FileReader("output.txt")) {

        // Leemos el primer carácter del fichero
        // read() devuelve:
        // - un entero (código ASCII/Unicode del carácter)
        // - -1 cuando llega al final del fichero
        ch = fr.read();

        // Mientras no sea fin de fichero (-1)
        while (ch != -1) {

            // Convertimos el entero a carácter
            // y lo mostramos por pantalla
            System.out.print((char) ch);

            // Leemos el siguiente carácter
            ch = fr.read();
        }

    } catch (IOException fe) {

        // Se ejecuta si ocurre algún error de lectura
        System.out.println("Error de E/S");
    }
}

Línea a línea: BufferedReader

Otro ejemplo en el que se leen líneas completas. En este caso utilizamos BufferedReader

/**
 * Lee el fichero "datos.txt" línea por línea
 * utilizando BufferedReader.
 *
 * - Usa try-with-resources → cierre automático
 * - Lee con readLine()
 * - Muestra cada línea por pantalla
 */
public static void main(String[] args) {

    // try-with-resources:
    // El BufferedReader se cerrará automáticamente al finalizar el bloque
    try (

        BufferedReader in = new BufferedReader(
                     new FileReader("datos.txt"))
    ) {

        // Leemos la primera línea del fichero
        // readLine() devuelve:
        // - Un String con la línea
        // - null si llega al final del fichero
        String cadena = in.readLine();

        // Mientras no sea fin de fichero
        while (cadena != null) {

            // Mostramos la línea por pantalla
            System.out.println(cadena);

            // Leemos la siguiente línea
            cadena = in.readLine();
        }

    } catch (FileNotFoundException e) {

        // Se ejecuta si el fichero no existe
        System.out.println("ERROR. Archivo no encontrado");

    } catch (IOException e) {

        // Se ejecuta si ocurre error de lectura
        System.out.println(e.getMessage());
    }
}

Lectura de ficheros de texto con Scanner

A partir de Java 5 se puede leer un fichero de texto utilizando la clase Scanner igual que si leyéramos por teclado. Para ello se le pasa al constructor de Scanner el objeto FileReader asociado al fichero. Esta operación lanza una excepción FileNotFoundException.

Lectura de un fichero de texto con una serie de enteros separados por secuencias de espacios y tabuladores, incluso en líneas distintas

12 34 56 32 43

/**
 * Método main
 *
 * Lee números enteros desde el fichero "datos.txt"
 * utilizando:
 *
 * - FileInputStream → abre el fichero
 * - Scanner → permite leer números fácilmente
 */
public static void main(String[] args) {

    try (
        FileInputStream flujo = new FileInputStream("datos.txt"); // conexión con el fichero
        var sc = new Scanner(flujo);                              // lector de tokens (números, texto, etc.)
    ) {

        // Mientras haya datos disponibles en el fichero
        // hasNext() devuelve true si hay más tokens
        while (sc.hasNext()) {

            // Leemos el siguiente número entero
            // nextInt() lanza excepción si el dato no es un entero
            int n = sc.nextInt();

            // Mostramos el número leído
            System.out.print(n + " ");
        }

    } catch (FileNotFoundException e) {

        // Se ejecuta si el fichero no existe
        System.out.println("ERROR. Archivo no encontrado");

    } catch (IOException e) {

        // Se ejecuta si ocurre error de entrada/salida
        System.out.println("ERROR de E/S");
    }
}