Formación informática

Java | Joomla | MySQL

Curso de Java - Tema 29: lectura y escritura en ficheros de texto

Lectura y Escritura en Ficheros de Texto

Hasta ahora hemos utilizado estructuras de Java que almacenaban la información introducida en la memoria RAM de nuestro ordenador mientras la aplicación estaba corriendo. Desde un punto de vista didáctico no influye en nada puesto que hemos aprendido el proceso correcto de hacer las cosas. Sin embargo, los datos introducidos son volátiles y se pierden al parar la ejecución de la aplicación.

En el día a día de nuestras nos interesa poder guardar datos que después recuperaremos para usarlos de la forma que mejor nos venga. Hay varios métodos para almacenar la información en el disco duro: en un archivo de texto, en un archivo en formato binario o en bases de datos. Aquí vamos a ver la primera.

Clases a usar

Para leer y/o escribir de/en un fichero tenemos que hacer uso de numerosas clases de Java para crear objetos que nos permitan usar sus métodos. En función del caso particular en el que estemos tendremos que usar todas o parte de las siguientes clases:

  1. Usaremos la clase File para crear un objeto de tipo fichero que nos permite acceder a él. A este objeto tenemos que pasarle la ruta absoluta del fichero. El identificador más adecuado es fichero. En caso de no indicar una ruta, Netbeans asumirá que el archivo está en la carpeta principal del proyecto.
  2. Usaremos la clase FileReader para leer el contenido del objeto creado con File. El identificador más adecuado es lector.
  3. Usaremos la clase BufferedReader para devolver el contenido leído con el objeto FileReader. Usaremos el método readLine() para leer cada línea que guardaremos en un objeto de la clase String. El identificador más adecuado es buffer.
  4. Usaremos la clase String para almacenar cada línea del archivo que nos suministra el buffer. El identificador más adecuado es línea.
  5. Usaremos la clase StringBuilder para juntar todo el contenido devuelto por el buffer y poder usar sus métodos de acuerdo a las necesidades. Por ejemplo una frase.
  6. Usaremos un objeto ArrayList para almacenar listados de números que tengamos que analizar de alguna forma más tarde. Usamos este tipo de colección porque es un objeto dinámico.
  7. Usaremos la clase BufferedWriter para almacenar temporalmente el texto que se desea escribir en el archivo.
  8. Usaremos la clase FileWriter para escribir en el fichero en el texto, usando el objeto creado con la clase FileWriter.
  9. Usaremos la clase FileNotFoundException para realizar el tratamiento de excepciones relativas a la búsqueda del archivo.
  10. Usaremos la clase IOException para realizar el tratamiento de excepciones en la entrada y salida de datos.

Como proceso reducido puede decirse que la filosofía de acceso a la lectura y escritura a los ficheros, siempre es la misma. Buffer, que envuelve a Reader, que a su vez envuelve al fichero (o stream). Tanto para la lectura como la escritura es obligatorio realizar el tratamiento de las excepciones que pueden ocurrir durante el proceso.

Proceso de lectura

El proceso comienza por importar todas las clases que vamos a usar:

import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;

El siguiente paso es instanciar todos los objetos necesarios:

  • Uno de la clase File que nos permite acceder al archivo. A este objeto tenemos que pasarle como argumento la ruta absoluta del archivo, que es la permite acceder a él sin confusiones. Tenemos que tener cuidado con el uso de las barras que separan los directorios para usar la secuencia de escape adecuada de acuerdo al sistema operativo que estemos usando.
  • Uno de tipo FileReader que será el encargado de leer el archivo.
  • Uno de tipo BufferedReader para devolver el contenido. Usaremos el método readline para almacenar el texto línea a línea en una variable de tipo String.
  • Ahora que tenemos capturada una línea del archivo de texto podemos procesarlo para realizar las transformaciones necesarias en el caso de que el contenido del archivo venga formateado (archivo separados por comas, dos puntos…) o tengamos que unir texto disperso, por poner dos ejemplos.
    • En el caso de ser un archivo con varias líneas de texto que tenemos que unir, usaremos un objeto de StringBuilder para almacenar el contenido completo usando el método append en cada una de las vueltas que realizamos con readline.
    • En el caso de archivos formateados, tenemos que hacer dos pasos. En el primero usamos un array para almacenar los datos divididos. A continuación usamos un objeto para introducir los datos en un objeto de tipo colección.
  • No hay que olvidar cerrar las conexiones realizadas con el lector y el buffer para liberar los recursos usados por la máquina virtual de Java para realizar el proceso.

El siguiente paso es usar todos estos objetos y sus métodos para obtener el resultado que deseamos. Veamos cuál sería la sintaxis genérica:

//Variable para almacenar el fichero e inicialización
File fichero;
fichero = new File("ruta_absoluta_del_fichero_de_texto"); 
// Variable para leer el texto
FileReader lector;
//Variable para almacenar el texto leído
BufferedReader buffer;
//Variable que almacena cada línea leída
String linea;
//Variable que almacenará el texto concatenado
StringBuilder frase = new StringBuilder();
//ArrayList para almacenar listados separados por comas, tabuladores…
StringBuilder frase = new StringBuilder();
	  
//Tratamiento de excepciones
try {
		// Objeto de lectura del fichero 
		lector = new FileReader(fichero);
		// Objeto de buffer
		buffer = new BufferedReader(lector);
		//Lectura del archivo de texto y concatenación del texto leído añadiendo un espacio
		while ((linea = buffer.readLine()) != null) {
				instrucciones_adecuadas_a_cada_caso;
	}
	//Procesado posterior de las instrucciones dentro del bucle
	instrucciones_adecuadas_a_cada_caso;
            
	//Mostramos los mensajes adecuados a cada caso
	System.out.println("”);
            
	//Cerramos el lector y el buffer
	lector.close();
	buffer.close();

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

Ejemplos de sintaxis en el bucle while

Si tenemos un archivo de texto que contiene varias líneas de texto que queremos unir, el proceso consiste en usar un objeto StringBuilder, llamado frase, para poder usar el método append para concatenar todo el contenido devuelto por el buffer (línea) hasta que éste esté vacío. Posteriormente podemos realizar el tratamiento necesario al objeto StringBuilder. La sintaxis genérica es:

while ((linea = buffer.readLine()) != null) {
                frase.append(linea + " ");
            }
            //Añadimos el punto final a la frase
            frase.replace(frase.length() - 1, frase.length(), ".");
            //Mostramos la frase completa
            System.out.println("La frase unida es: " + frase);

Si tenemos un archivo de texto que contiene un listado de valores separados por caracteres especiales (comas, punto y coma, barra vertical…) y queremos realizar cálculos con su contenido, el proceso consiste en usar un Array, llamado números, para almacenar el contenido devuelto por el buffer (línea) usando los métodos necesarios para poder separar el contenido de acuerdo al carácter especial presente en el archivo. Usamos un bucle for o for each para recorrer todo el array y realizar todos los cálculos. La sintaxis genérica para obtener la suma y media de los valores es:

while ((linea = buffer.readLine()) != null) {                
                numeros = linea.toString().split("[carácter_especial_división]");
                
               for (String s : numeros) {
                    suma += Double.parseDouble(s);
                    contador++;
                }
                media = suma / numeros.length;

Un ejemplo sería el siguiente código mediante el cual creamos una aplicación que nos permite leer el contenido de un archivo de texto que contiene una frase separada por retornos de carro:

package principal;

import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * @author José María Torres Corral
 */
public class Main {
  
    public static void main(String[] args) {        
        //Variable para almacenar el fichero e inicialización
        File fichero;
        fichero = new File("texto.txt"); //Objeto del fichero
        // Variable para leer el texto
        FileReader lector;
        //Variable para almacenar el texto leído
        BufferedReader buffer;
        //Variable que almacena cada línea leída
        String linea;
        //Variable que almacenará el texto concatenado
        StringBuilder frase = new StringBuilder();

        try {
            // Objeto de lectura del fichero 
            lector = new FileReader(fichero);
            // Objeto de buffer
            buffer = new BufferedReader(lector);
            //Lectura del archivo de texto y concatenación del texto leído añadiendo un espacio
            while ((linea = buffer.readLine()) != null) {
                frase.append(linea + " ");
            }
            //Añadimos el punto final a la frase
            frase.replace(frase.length() - 1, frase.length(), ".");
            //Mostramos la frase completa
            System.out.println("La frase unida es: " + frase);
            //Cerramos el lector y el buffer
            buffer.close();
            lector.close();            

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

Proceso de escritura

Al igual que sucedía con la lectura desde ficheros de texto, el tratamiento de excepciones es obligatorio para que la aplicación se ejecute.

Cómo normalmente vamos a querer escribir en un fichero de texto datos relacionados de alguna forma, tendremos que usar uno o varios objetos de tipo colección para almacenar temporalmente los datos que posteriormente vamos a usar en con los objetos de escritura. Una forma más o menos sencilla de hacerlo es dividir el proceso en dos pasos. En el primero, recopilamos los datos de las variables en un array con las dimensiones adecuadas al número de propiedades a recoger. En el segundo, usamos el array para introducir los datos en un arraylist desde el cuál escribiremos. Por lo tanto, tendremos realizar las importaciones necesarias.

El proceso comienza por importar las clases que tenemos que usar: File, FileWriter, BufferedWriter junto con aquellas clases que usemos para almacenar los datos y las que realizan el tratamiento de excepciones. La sintaxis es esta:

import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter
import java.io.IOException;
import java.util.ArrayList;

//Declaramos el array con las dimensiones adecuadas
String nombre_array [] = new String[numero_propiedades];
// Declaramos e inicializamos el ArrayList para guardar el array anterior
ArrayList  nombre_arraylist = new ArrayList();

A continuación, declaramos los objetos necesarios:

//Objeto de tipo file para acceder al fichero
File fichero;
//Objeto de tipo FileWritter para escribir 
FileWriter escritor;
//Objeto de tipo BufferedWriter
BufferedWriter buffere;
//Objeto de tipo Scanner
Scanner teclado = new Scanner(System.in);

Pedimos la introducción de los datos, teniendo que mostrar tantos mensajes como datos haya que recopilar:

System.out.println("Mensaje variable 1");
nombre_array[0] = teclado.nextLine();
System.out.println("Mensaje variable 2");
nombre_array [1] = teclado.nextLine();

Introducimos los datos en el ArrayList usando sus métodos:

nombre_arraylist.add(atributo);

Realizamos el tratamiento de excepciones y las operaciones necesarias para escribir:

try {
	//Creamos el objeto fichero   
	fichero = new File("ruta_absoluta del fichero");
	//Creamos el objeto escritor con actualización
	escritor = new FileWriter(fichero, condición_actualización);

	//Usamos un bucle for each para introducir las notas usando el escritor
	for (String[] nombre : nombre_ArrayList) {
		escritor.write(nombre[0]);
		escritor.write(nombre[1]);                     ⋮
	}
	
	//Cerramos el escritor
	escritor.close();

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

El siguiente código nos permite crear una aplicación para introducir las notas de los alumnos de un curso en un fichero de texto:

/*
 * Aplicación para escribir en un fichero de texto las notas de los alumnos
 */
package principal;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

/**
 *
 * @author José María Torres Corral
 */
public class Main {

    public static void main(String[] args) throws IOException {

        //Declaramos el array con dos posiciones
        String nota[] = new String[2];
        // Usamos un arrayList que contendrá un array para almacenar las notas
        ArrayList alumnoNota = new ArrayList();
        //Objeto de tipo file para acceder al fichero
        File fichero;
        //Objeto de tipo FileWritter para escribir 
        FileWriter escritor;
        //Objeto de tipo Scanner
        Scanner teclado = new Scanner(System.in);

        //Pedimos la introducción de los datos y los introducimos en las posiciones del array
        System.out.println("Introduce el nombre del alumno, por favor.");
        nota[0] = teclado.nextLine();
        System.out.println("Introduce las notas parciales separadas por comas, por favor.");
        nota[1] = teclado.nextLine();

        //Introducimos las notas en el ArrayList
        alumnoNota.add(nota);
             
        try {
            //Creamos el objeto fichero   
            fichero = new File("notas.txt");
            //Creamos el objeto escritor con actualización
            escritor = new FileWriter(fichero, true);

            //Usamos un bucle for each para introducir las notas en el archivo usando el escritor
            for (String[] alumno : alumnoNota) {
                escritor.write(alumno[0]+ " ");
                escritor.write(alumno[1] + "\n");
            }
            //Cerramos el escritor
            escritor.close();

        } catch (IOException ex) {
            System.out.println(ex.getMessage());
        }
    }
}
Curso de Java - Tema 28: creación y uso de menús por línea de comandos | Curso de Java - Tema 30: lectura y escritura en ficheros en formato binario
Curso de Java - Índice Ejercicios Nivel Medio

Escribir un comentario

Aunque los comentarios no expresan la opinión del administrador del sitio web, éste si que tiene una responsabilidad legal sobre lo que aparece. Por lo tanto, habrá una labor de moderación de los mensajes. No se permitirán mensajes ofensivos ni publicidad


Código de seguridad
Refescar

Solicitamos su permiso para obtener datos estadísticos de su navegación en esta web, en cumplimiento del Real Decreto-Ley 13/2012, de 30 de marzo. Si continúa navegando consideramos que acepta el uso de cookies. . Más información