Operaciones con ficheros

Ejercicio resuelto

Crear un programa que sea capaz de contar cuántas vocales hay en un fichero.

El programa padre debe lanzar cinco procesos hijo, donde cada uno de ellos se ocupará de contar una vocal concreta (que puede ser minúscula o mayúscula). Cada subproceso que cuenta vocales deberá dejar el resultado en un fichero. El programa padre se ocupará de recuperar los resultados de los ficheros, sumar todos los subtotales y mostrar el resultado final en pantalla.

Operaciones con ficheros

Tanto en este ejercicio como en muchos otros vamos a necesitar realizar ciertas operaciones con ficheros. Para aumentar nuestra productividad utilizaremos una clase llamada UtilidadesFicheros que nos permita realizar ciertas tareas como las siguientes:

import java.io.*;
import java.util.ArrayList;

public class UtilidadesFicheros {
  • Obtener un objeto BufferedReader a partir de un nombre de fichero de tipo String. Llamaremos a este método getBufferedReader y lo utilizaremos para poder manejar un fichero mediante una clase de muy alto nivel que nos facilita la lectura de ficheros. En el listado adjunto se puede consultar dicho método.
  public static BufferedReader getBufferedReader(String nombreFichero) throws FileNotFoundException {

    FileReader lector;
    lector = new FileReader(nombreFichero);
    BufferedReader bufferedReader;
    bufferedReader = new BufferedReader(lector);

    return bufferedReader;
  }
  • De la misma forma crearemos un método getPrintWriter que nos devuelva un objeto de la clase PrintWriter para poder realizar fácilmente operaciones de escritura en ficheros. En el listado adjunto se muestra el código.
  public static PrintWriter getPrintWriter(String nombreFichero) throws IOException {

    PrintWriter printWriter;
    FileWriter fileWriter;
    fileWriter = new FileWriter(nombreFichero);
    printWriter = new PrintWriter(fileWriter);

    return printWriter;
  }
  • Aunque nos estamos anticipando, puede ser útil tener un método que dado un nombre de fichero nos devuelva un ArrayList<String> con todas las líneas que hay en el fichero. En este ejercicio no lo usaremos. Este método podría implementarse así:
  public static ArrayList<String> getLineasFichero(String nombreFichero) throws IOException {

    ArrayList<String> lineas = new ArrayList<String>();
    BufferedReader bfr = getBufferedReader(nombreFichero);
    //Leemos líneas del fichero...
    String linea = bfr.readLine();
    while (linea != null) {
        //Y las añadimos al array
        lineas.add(linea);
        linea = bfr.readLine();
    }
    //Fin del bucle que lee líneas
    return lineas;
  }
} //fin de la clase UtilidadesFicheros

Procesado de ficheros

Necesitaremos una clase ProcesadorFichero que nos permita procesar los ficheros de la forma pedida. Antes de crear un programa multiproceso empezaremos por crear una clase simple que nos resuelva este problema.

Dicha clase tendrá un método hacerRecuento que resuelva el problema de contar el número de apariciones en un fichero dejando el total de apariciones en un fichero de salida distintos. En el código adjunto podemos ver como podría implementarse dicho método.

// Dado un fichero de entrada y una letra
// contamos cuantas veces aparece dicha letra
// y dejamos el recuento en un fichero de salida

import java.io.*;

public class ProcesadorFichero {
  public static void hacerRecuento(String fichEntrada, String letra,String fichSalida) throws FileNotFoundException,IOException {

        BufferedReader br;
        br = UtilidadesFicheros.getBufferedReader(fichEntrada);
        PrintWriter pw;
        pw = UtilidadesFicheros.getPrintWriter(fichSalida);
        String lineaLeida;
        lineaLeida = br.readLine();
        int totalVocales = 0;
        //Mientras no queden líneas....
        while (lineaLeida != null) {
            //...recorremos la linea...
            for (int i = 0; i < lineaLeida.length(); i++) {
                char letraLeida = lineaLeida.charAt(i);
                char letraPasada = letra.charAt(0);
                // incrementamos el contador
                if (letraLeida == letraPasada) {
                    totalVocales++;
                }
            }
            // Pasamos a la siguiente linea
            lineaLeida = br.readLine();
        }
        //Escribimos el total de vocales
        //en el fichero de salida
        pw.println(totalVocales);
        pw.flush();
        //Y cerramos los ficheros
        pw.close();
        br.close();
  }

La clase ProcesadorFichero será lanzada desde otra clase que llamaremos Lanzador. Nuestra ProcesadorFichero recogerá en su método main los siguientes parámetros:

  1. El nombre del fichero a procesar. Lo llamaremos nombreFicheroEntrada y estará en la posición 0 de los argumentos.
  2. La letra de la que hay que hacer el recuento de apariciones. La llamaremos letra y estará en la posición 1.
  3. El nombre del fichero donde se dejarán los resultados. Lo llamaremos nombreFicheroResultado y estará en la posición 1 de los argumentos.

El código del main se muestra a continuación.

/**
* Dado un fichero pasado como argumento, contará cuantas
* apariciones hay de una cierta vocal (pasada como argumento)
* y dejará la cantidad en otro fichero (también pasado como
* argumento)
* @throws IOException
* @throws FileNotFoundException  
*/
  public static void main(String[] args) throws FileNotFoundException, IOException {

    String nombreFicheroEntrada = args[0];
    String letra = args[1];
    String nombreFicheroResultado = args[2];
    hacerRecuento(nombreFicheroEntrada, letra, nombreFicheroResultado);
  }
} //fin de la clase ProcesadorFichero

Lanzamiento de los procesos

La clase Lanzador tendrá un método main que se encargará de varias cosas:

  1. Recoger el primer parámetro (args[0]), que contendrá el fichero a procesar.
  2. Una vez recogidos los parámetros, se lanzarán los procesos utilizando la clase ProcessBuilder.
  3. Los procesos se ejecutarán y después recogeremos los resultados de los ficheros.

En el código siguiente puede verse el método main de esta clase Lanzador. La recogida de resultados se deja como ejercicio:

public class LanzadorProcesadorFichero {

    public static void main(String[] args) throws IOException, InterruptedException {
           String ficheroEntrada;
           ficheroEntrada = args[0];
           String[] vocales = {"a", "e", "i", "o", "u"};





    }
}

¿Recogida de resultados?

Mejora: Esperar a que terminen todos los procesos en lugar de un tiempo al azar.

Mejora: contar las mayúsculas, las minúsculas y los acentos.

Deja una respuesta