Archivos

Un vendedor desea crear una base de datos con los productos que vende, las unidades disponibles y sus precios, con el propósito de no vender productos que no están en bodega y no vender a precios equivocados.



El lugar lógico en donde almacenar esta base de datos es en un archivo en disco. Esta información no se puede tener permanentemente en la memoria del computador, porque

      1. se borra cuando se apaga el computador, y

      2. su tamaño es limitado (típicamente unos 64 megabytes, que equivalen a 1024*1024 bytes).



En cambio, el disco permite almacenar datos en forma

(i) permanente o persitente (no se borra al apagar el computador), y

(ii) masiva (típicamente unos 4 gigabytes, que equivalen a 4096 megabytes).



Desventaja del disco: la manipulación de datos en disco es mucho más lenta que en la memoria del computador.





Archivos



Los computadores almacena la información permanente en dispositivos de almacenamientos, tales como discos duros, diskettes y discos compactos. La información almacenada puede ser muy variada, textos, aplicaciones (programas), imágenes o sonidos. Sin embargo, todo esta información se guarda en elementos llamados "archivos".



El tamaño de un archivo puede ir desde 0 bytes (un archivo vacío) hasta archivos de varios gigabytes. Dependiendo del sistema operativo, estos archivos se organizan en estructuras similares a árboles llamados directorios. Cada archivo se identifica mediante un nombre.



Archivos de texto



Los archivos de texto son el tipo más simple de archivo. Están compuestos por líneas de texto, cada línea contiene palabras (o símbolos) separadas por espacios. Uno puede representar un archivo de texto como un conjunto de líneas de ancho variable:



Puro Chile

es tu cielo azulado

puras brisas

...



En un archivo de texto se pueden guardar distintas cosas:



canciones

fuentes de programas

bases de datos simples

diarios

etc



Un editor de texto es un programa que permite leer y modificar un archivo de texto. Por ejemplo, Notepad de Windows es un editor de texto. Los archivos de texto se caracterizan por ser "planos", es decir, todas las letras tienen el mismo formato y no hay palabras subrayadas, en negrita, o letras de distinto tamaño o ancho.



Los archivos binarios, a diferencia de los archivos de texto, guardan información que no se puede representar por letras: imágenes o texto con formato. Al abrir estos archivos con un editor de texto, el editor se llena de símbolos extraños, pues trata de interpretar la información dentro del archivo de una forma incorrecta.



Las aplicaciones (ejecutables), también se almacenan en archivos, como secuencias de unos y ceros. Tampoco puede mirarse su contenido con un editor de texto.



Escritura de archivos



En este curso crearemos archivos mediante fopen y fclose, y el “tipo de variable” FILE *, funciones de la librería stdio.h.



Por ejemplo, consideremos un programa que escribe un archivo con nombres de productos que ingresa el usuario. El diálogo entre programa y usuario será:



producto ? jabon Lux

producto ? pasta de dientes Odontine

producto ? ...



El programa debe escribir el archivo "productos.txt" de tal forma que su contenido sea el siguiente:



Archivo: productos.txt



jabón Lux

pasta de dientes Odontine

champú Sedal

...



El programa que realiza este diálogo y escribe el archivo es el siguiente:



  1. FILE *F;

  2. char producto[20];

  3. F = fopen (“producto.txt”,”w”);

  4. printf("Ingrese el nombre de un producto: ");

  5. scanf(“%s”,producto);

  6. while (strcmp(producto,"fin")!=0)

  7. {

  8. fprintf (F,”%s”,producto);

  9. printf("Ingrese el nombre de un producto: ");

  10. scanf(“%s”,producto);

  11. }

  12. fclose(F);

En la línea 1 el programa fabrica/construye un puntero a una estructura donde almacenará la información de ``productos.txt''. Se indica como argumento el nombre del archivo que se va a escribir y que el tipo de archivo será de escritura (si hubiera sido “r” sería lectura). En la estructura tipo FILE y cuyo nombre en este ejemplo es F queda la información del archivo.



Para escribir en el archivo se utiliza la función fprintf, de la misma forma en que se utilizaba printf sólo que a ésta función se le asigna un archivo como primer parámetro. por tanto, para leer un archivo se utilizará fscanf al igual que nuestra conocida scanf, siempre que el archivo sea abierto para lectura.



fprintf no escribe los datos de inmediato en el disco, si no que espera a formar un lote grande y luego escribirlos en conjunto. Esto resulta más rápido que escribirlos de a uno, porque escribir un byte en disco toma el mismo tiempo que escribir 4 kilobytes. A eso se le conoce como BUFFER.



Si se desea escribir inmediatamente a disco, después de abrir el archivo se debe utilizar la función fflush (FILE *).



Función fclose(FILE *)



fclose(F) ordena a escr concluir la escritura del archivo (si hay un lote pendiente lo escribe) referenciado en F. Después de invocar fclose(F) no es posible volver a escribir utilizando F, a menos que se le asigne otro archivo. La improtancia de fclose radica en que el archivo no será creado hasta que esta función no se ejecute.



Lectura de un archivo



Se desea escribir un programa que despliegue en pantalla los productos almacenados en el archivo "productos.txt''. El programa es:



  1. FILE *F, char linea[64];

  2. F=fopen(“producto.txt”,”r”);

  3. fgets(linea,64,F);

  4. while ( !feof(F) )

  5. {

  6. printf(linea);

  7. fgets(linea,64,F);

  8. }

  9. fclose(F);;

Función fgets(char *linea, int max, FILE *F)



Como se habrán dado cuenta no utilizamos para este ejemplo la función fscanf sino que la función fgets, ésto porque la primera lee palabra por palabra y la segunda línea por línea. Los parámetros de fgets son: el string donde se dejará lo leído, el máximo de carácteres que se leerán del archivo (si la línea del archivo tiene menos que max entonces se marca en linea con el carácter '\0') y el puntero a la estructura del archivo.



IMPORTANTE: Si se ha producido un EOF (End of File, o lectura de la marca de final de archivo) entonces fgets retorna NULL.



Función feof(FILE *F)



feof(FILE *F): consulta si se alcanzó el final del archivo (end of file). Esta operación retorna un valor entero y por lo tanto se coloca como condición en un if o un while. Retorna verdadero (1) cuando la última operación de lectura se hizo más allá del final del archivo.



Pon tus conocimientos a prueba



Escribe un programa que dialogue con el usuario para escribir un archivo "productos-precios.txt'' que incluya producto y precio en cada línea. El programa debe aprovechar los productos almacenados en "productos.txt'' para que el usuario no tenga que digitarlos nuevamente. El diálogo debe ser el siguiente:



Precio de jabon Lux ? 344

Precio de pasta de dientes Odontine ? 415

...



El archivo productos-precios.txt escrito debe ser:



jabón Lux 344

pasta de dientes Odontine 415

champú Sedal 507

...



Solución:



  1. FILE *PROD, *PRODPRE;

  2. char linea[64];

  3. int precio;

  4. PROD = fopen(“producto.txt”,”r”);

  5. PRODPRE = fopen (“productos-precio.txt”,”w”);

  6. fgets(linea,64,PROD);

  7. while ( !feof(PROD))

  8. {

  9. printF("Precio de %s? ",linea);

  10. scanf (“%d”,&precio);

  11. fprintf(PRODPRE,”%s %d\n”,prod,precio);

  1. fgets(linea,64,PROD);

  1. }

  2. fclose(PROD);

  3. fclose(PRODPRE);

Campos de datos



¿ Cómo harías un programa que determine a partir del archivo "productos-precios.txt'' el producto más barato?

En este caso se presenta un problema que consiste en cómo separar el contenido de una línea en nombre del producto y precio.



Si se lee la primera línea mediante fgets se tiene el problema que se lee la línea completa y se guarda en una sola variable char[], que habría que "quebrar" de algún modo para trabajar con sus componentes.



El siguiente codigo es erróneo:

  1. 1.FILE *PROD, *PRODPRE;

  2. char linea[64];

  3. int precio;

  4. PROD = fopen(“producto.txt”,”r”);

  5. fgets(linea,64,PROD);

  6. fscanf(PROD,”%d”,&precio);



La operación fgets(linea,64,PROD) leerá toda la línea ("jabon Lux 344"). Cuando se lea el precio con lect.readInt() tratará de leer "pasta" como un número lo que constituye un error en tiempo de ejecución.



La solución consiste en escribir el archivo delimitando los datos por un caracter especial como dos puntos (:). Para ello es necesario cambiar la línea 11 a



11. fprintf(PRODPRE,”%s:%d\n”,prod,precio);



De esta forma, el archivo en disco tendrá la siguiente estructura:



jabón Lux:344

pasta de dientes Odontine:415

champú Sedal:507

...



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:



  1. char linea[64], prod[64], *p;

  2. int precio;

  3. fgets(linea,64,PROD);

  4. while ( !feof(PROD) )

  5. {

  6. int pos=0;

  7. char *p=linea;

  8. while (*p++ != ':') pos++;

  9. strncpy (prod, linea, pos);

  10. precio = atoi (p); /* CONVIERTE DE STRING A ENTERO */

  11. ...

  12. fgets(linea,64,PROD);

  13. }

  14. ...

La función char *strchr(char *s, char c)



La complicada línea escrita en rojo ya tiene su función en la librería string.h. la función strchr recibe un string s y un carácter c y retorna un puntero a la primera aparición de c en s, o NULL si no la hay.

Además, la función atoi convierte el string que recibe como parámetro en un entero, así como ella está también atof.



Pon tus conocimientos a prueba



Modifica el programa de modo que se indique:



Problema resuelto



En el archivo "nombres.txt" se encuentran todos los nombres de los alumnos del curso, de la forma un nombre por línea. Suponiendo que el archivo se encuentra en orden alfabetico, escribe un programa que diga cual es el nombre que más se repite en el curso y cuantas veces lo hace.



Esta solución es bastante complicada... ¿cómo se puede hacer mas simple?



  1. int masRepetida=0, repeticiones=0;

  2. FILE *F=fopen (“nombres.txt”,”r”);

  3. char nombre[64],nombreMasrepetido[64], exNombre[64];

  4. fgets(nombre, 64, F);

  5. strcpy(exNombre,nombre);

  6. while (!feof(F))

  7. {

  8. if (strcmp(nombre,exnombre)==0)

  9. repeticiones++;

  10. if (repeticiones > masRepetida)

  11. {

  12. masRepetida=repeticiones;

  13. nombreMasRepetido=nombre;

  14. }

  15. else

  16. repeticiones=1;

  17. strcpy(exNombre, nombre);

  18. fgets(nombre, 64, F);

  19. }

  20. printf ("El nombre mas comun es %s",nombreMasRepetido);

  21. printf (" y aparece %d veces”,masRepetida);