Lunes 19 de Abril

Aplicación de Archivos: Bases de Datos

Objetivos: Mostrar como se pueden escribir archivos con múltiples datos por línea, de modo que después puedan ser leídos fácilmente.

Temas:


Campos de datos

Escribir un programa que determine a partir del archivo ``productos-precios.txt'' el producto más barato.

Problema: ¿Cómo separar el contenido de una línea en nombre del producto y precio? Si se lee la primera línea mediante:

    String prod= lect.readString();
    int precio= lect.readInt();
la operación lect.readString() leerá sólo una palabra del nombre del producto ("jabon"). Cuando se lea el precio con lect.readInt() tratará de leer "Lux" como un número lo que constituye un error en tiempo de ejecución.

Solución:

Al escribir el archivo, delimitar los datos por un caracter especial como ":". Para ello es necesario cambiar la línea (*) en el programa que escribe ``productos-precios.txt'' por:

      escr.print(nombre+":"+precio); // (*)
De esta forma, el archivo en disco tendrá la siguiente estructura:

    jabon Lux:344
    pasta de dientes Odontine:415
    ...
En este tipo de archivos los datos que quedan delimitados por ":" se denominan campos (fields). Esta estrategia es muy útil para poder incluir varios datos en una misma línea y después poder separarlos cómodamente ubicando la posición de los ":".

Por ejemplo, el siguiente código lee las líneas de un archivo, separando los campos de datos y dejandola en variables independientes. Para ubicar el ":" invoca la función indexOf.

    String line= lect.readLine();
    while ( ! lect.eofReached() ) {
      int pos= indexOf(line, ":");
      String prod= substring(line, 0, pos);
      int precio= parseInt( substring(line, pos+1) );
      ...
    }
    ...
Si bien, esta solución permite resolver el problema, su aplicación puede resultar en muchos errores. Para minimizar los errores de programación resulta conveniente usar la clase FieldParser, descrita a continuación.

La clase FieldParser

Para separar las líneas en sus múltiples campos, en este curso utilizaremos la clase FieldParser. Esta clase provee de objetos capaces de obtener uno a uno los campos de datos que hay en un string.

Por ejemplo, supongamos que el string linea contiene el nombre de un producto, su precio y las unidades disponibles, todos separados por ":". Para obtener estos campos se escribe el siguiente código:

    FieldParser decod= new FieldParser(linea,":");
    String prod= decod.readString();
    int precio= decod.readInt();
    int unidades= decod.readInt();
Si linea fuese "jabon Lux:344:25", entonces el valor asignado a prod sería "jabon Lux", precio sería 344 y unidades 25.

Con esta clase, el siguiente programa muestra en pantalla el contenido del archivo ``productos-precios.txt'':

    TextReader lect= new TextReader("productos-precios.txt");
    String linea= lect.readLine();
    while ( ! lect.eofReached() ) {
      FieldParser decod= new FieldParser(linea,":");
      String prod= decod.readString();
      int precio= decod.readInt();
      println(prod+" "+precio); // muestra en pantalla producto y precio
      linea= lect.readLine();
    }
    lect.close();
Observe que en este caso sólo hay 2 campos en cada línea.


Ejercicio:

Se tiene un archivo que contiene los siguientes campos: nombre de producto, precio en pesos, unidades disponibles, demanda promedio diaria. Escriba un programa que dialogue con el usuario para obtener el nombre del archivo y luego indique:

Solución:

    print("Ingrese el nombre del archivo de productos: ");
    String archProd= readString();
    TextReader lect= new TextReader(archProd);
    int cont= 0; // numero de productos leidos
    String linea= lect.readLine();
    while ( ! lect.eofReached() ) {
      FieldParser decod= new FieldParser(linea,":");
      String prod= decod.readString();
      int precio= decod.readInt();
      int unidades= decod.readInt();
      double demanda= decod.readDouble();

      cont= cont+1; // Se leyo un producto mas
      if (unidades==0)
        println("El producto "+prod+" esta agotado");
      String linea= lect.readLine();
    }
    lect.close();
    println("Se leyeron "+cont+" productos");
Suponga que ahora se pide además generar una orden de compra para todos los productos que estén agotados o que estén en peligro de agotarse. Los productos que están por agotarse son aquellos que tengan unidades inferiores a la demanda diaria. Al ordenar un producto se pide la cantidad necesaria para completar 3 días de demanda. La orden de comprar que se debe generar es un archivo de nombre "orden.txt" que contiene los siguientes campos: nombre producto, unidades que se compran.

Solución: antes de entrar al ciclo hay que crear el archivo de órdenes.

    TextWriter escrOrden= new TextWriter("orden.txt");
    int contOrden= 0;
Por cada línea leída se realiza los siguiente:

     if (unidades<demanda) {
       escrOrden.println(prod+":"+trunc(3*demanda-unidades));
       contOrden= contOrden+1;
     }
Al final se concluye con:

    escrOrden.close(); // cerrar el archivo de ordenes
    println("Se ordeno la compra de "+contOrden+" productos");
Observación: en este tipo de programas que manipulan archivos, siempre es útil contar las líneas leídas y/o escritas. Estos contadores permiten verificar que la cantidad de datos procesada corresponde a la cantidad esperada.


Tarea:

El archivo ``productos.txt'' tiene la información descrita en el ejercicio anterior.