UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI PROGRAMA EDUCATIVO Licenciado en Sistemas Computacionales PLAN DE ESTUDIO 2009-2 CLAVE DE UNIDAD DE APRENDIZAJE 11294 NOMBRE DE LA UNIDAD DE APRENDIZAJE Programación Estructurada PRÁCTICA No. NOMBRE DE LA PRÁCTICA DURACIÓN (HORAS) 11 Archivos Texto 2 1. INTRODUCCIÓN Un archivo es un conjunto de datos estructurados en una colección de entidades elementales o básicas denominadas registros que son de igual tipo y constan a su vez de diferentes entidades de nivel más bajos denominadas campos. Hay dos tipos de archivos, archivos de texto y archivos binarios. En C, un archivo es un concepto lógico que puede aplicarse a muchas cosas desde archivos de disco hasta terminales o una impresora. 2. COMPETENCIA Elaborar programas de cómputo aplicando archivos de texto para el correcto almacenamiento de datos y recuperación de la información de manera secuencial, con una actitud positiva y honesta. 3. FUNDAMENTO Para trabajar con un archivo se asocia una estructura especial de tipo FILE con un archivo especifico realizando una operación de apertura. Una vez que el archivo está abierto, la información puede ser intercambiada entre este y el programa. El puntero a un archivo es el hilo común que unifica el sistema de E/S con un buffer. Un puntero a un archivo es un puntero a una información que define varias cosas sobre él, incluyendo el nombre, el estado y la posición actual del archivo. En esencia identifica un archivo específico y utiliza la secuencia asociada para dirigir el funcionamiento de las funciones de E/S con buffer. Un puntero a un archivo es una variable de tipo puntero al tipo FILE que se define en stdio.h. Un programa necesita utilizar punteros a archivos para leer o escribir en los mismos. Para obtener una variable de este tipo se utiliza una secuencia como la siguiente: FILE *puntero_archivo; Formuló Revisó José Alfredo Abad Padilla Josefina Mariscal Camacho Nombre y Firma del Maestro Nombre y Firma del Responsable de Programa Educativo Página 1 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI Apertura de un archivo La función fopen() abre una secuencia para que pueda ser utilizada y la asocia a un archivo. Su prototipo es: FILE *fopen(const char nombre_archivo, const char modo); Donde nombre_archivo es una cadena de caracteres que representa un nombre valido de archivo y puede incluir una especificación del directorio. Por su parte, la cadena modo determina como se abre el archivo. Si se usa fopen() para abrir un archivo para escritura, modo w, entonces cualquier archivo existente se sobrescribirá y si no existe un archivo con el mismo nombre, entonces se creará. Si se quiere añadir al final del archivo entonces debe usar el modo a. Si se usa a y no existe el archivo lo crea. La apertura de un archivo para las operaciones de lectura, modo r, requiere que exista el archivo. Si no existe, fopen() devolverá un error. Cierre de un archivo La función fclose() cierra una secuencia que fue abierta mediante una llamada a fopen(). Escribe toda la información que todavía se encuentre en el buffer en el archivo y realiza un cierre formal del archivo a nivel del sistema operativo. Un error en el cierre de una secuencia puede generar todo tipo de problemas, incluyendo la pérdida de datos, destrucción de archivos y posibles errores intermitentes en el programa. El prototipo de esta función es: int fclose(FILE *puntero_archivo); Funciones para manipular un archivo La función feof() determina cuando se ha alcanzado el fin del archivo. La función tiene el siguiente prototipo: int feof(FILE *puntero_archivo); La función rewind() pone el indicador de posición al principio del archivo indicado por su argumento. Su prototipo es: void rewind (FILE *puntero_archivo); La función ferror() determina si se ha producido en error en una operación sobre un archivo. Su prototipo es: int ferror(FILE *puntero_archivo); Devuelve cierto si se ha producido un error durante la última operación sobre el archivo. En caso contrario, devuelve falso. Debido a que cada operación sobre el archivo actualiza la condición de error, se debe llamar a ferror() inmediatamente después de la operación de este tipo; si no se hace así, el error puede perderse. La función remove() borra el archivo especificado. Su prototipo es el siguiente: int remove(char *nombre_archivo); Devuelve cero si tiene éxito. Si no un valor distinto de cero. Página 2 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI La función fflush() escribe todos los datos almacenados en el buffer sobre el archivo asociado a puntero_archivo. Su prototipo es: int fflush(FILE *puntero_archivo); Archivos Texto Un archivo de texto es una secuencia de caracteres organizadas en líneas terminadas por un carácter de nueva línea. En estos archivos se pueden almacenar canciones, fuentes de programas, base de datos simples, etc. 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. El operar con los archivos en modo texto facilita la compresión de los archivos por cualquier usuario que logre abrir el archivo con algún procesador de textos que permite leer el texto claro. Desgraciadamente es la forma más compleja de almacenar registros e información, así como recuperarla por parte de aplicaciones profesionales, por ello no es muy recomendable trabajar solo con el modo texto. Lectura de un archivo texto Las funciones fgetc() y fputc() pueden leer y escribir un carácter desde los archivos y hacia los archivos, respectivamente. Los prototipos de estas funciones son: int fgetc(FILE *puntero_archivo); int fputc(int caracter, FILE *puntero_archivo); Las funciones fgets() y fputs() pueden leer y escribir cadenas desde los archivos y hacia los archivos, respectivamente. Los prototipos de estas funciones son: char *fgets(char *cadena, int longitud_cadena, FILE *puntero_archivo); char *fputs(char *cadena, FILE *puntero_archivo); Las funciones fscanf() y fprintf() se comportan exactamente como scanf() y printf(), excepto que operan sobre archivo. Sus prototipos son: int fscanf(FILE *puntero_archivo, const char *cadena_de_forrmato, .....); int fprintf(FILE *puntero_archivo, const char *cadena_de_formato, .....); Las funciones fread() y fwrite() pueden leer y escribir bytes desde los archivos y hacia los archivos, respectivamente. Los prototipos de estas funciones son: size_t fread(void *registro, size_t tamaño_registro, size_t cantidad_registros, FILE *puntero_archivo); size_t fwrite(const void *registro, size_t tamaño_registro, size_t cantidad_registros, FILE *puntero_archivo); El siguiente ejemplo recibe texto hasta que se oprime el carácter “.“ , el cual es grabado en un archivo. #include <stdio.h> int main () { FILE *f; char car; Página 3 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI f = fopen("escrito.txt", "w"); //verificar si se pudo crear if( f == NULL ) { perror ("Error al crear archivo"); //funcion para imprimir error ocurrido, puede omitirse mensaje return (-1); } do { car = getc(stdin); fputc(car, f); } while(car!='.'); //Cerramos el archivo para que se grabe EOF fclose(f); //Abrimos ahora el archivo para lectura si no existe marca error f=fopen("escrito.txt", "r"); // Puntero con valor NULL es error de apertura if(f==NULL) { printf("Error: no se pudo abrir el archivo\n"); return (-1); } system(“clear”); do{ car=fgetc(f); //verificar si se termino el archivo if(car==EOF) break; printf("%c",car); } while(1); printf("\n"); //Cerramos el archivo para no tener problemas fclose(f); return 0; } El siguiente ejemplo utiliza un archivo texto para almacenar las estadísticas de la Liga de Futbol Mexicano. #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct { char equipo[30]; int jj; int jg; int je; int jp; int gf; int gc; Página 4 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI } Estadistica; int menu(); Estadistica setEstadistica(); void guardarEstadistica(Estadistica, char []); void leerArchivo(char []); int main(){ char archivo[]="ligaMX.txt"; Estadistica e; int opc; do{ opc = menu(); system("clear"); switch(opc){ case 1: e = setEstadistica(); guardarEstadistica(e, archivo); break; case 2: leerArchivo(archivo); getchar(); break; case 3: break; default: printf("No valida\n"); break; } }while(opc!=3); return 0; } //definición de las funciones int menu(){ int opc; system("clear"); puts("1. Guardar estadisticas de un equipo"); puts("2. Mostrar estadisticas"); puts("3. Salir"); printf("indica tu opcion: [ ]\b\b"); scanf("%d", &opc); getc(stdin); return opc; } Estadistica setEstadistica(){ Estadistica e; puts("Nombre del equipo:"); gets(e.equipo); puts("Juegos ganados:"); Página 5 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI scanf("%d", &e.jg); puts("Juegos empatados:"); scanf("%d", &e.je); puts("Juegos perdidos:"); scanf("%d", &e.jp); e.jj = e.jg + e.je +e.jp; puts("Goles a favor:"); scanf("%d", &e.gf); puts("Goles en contra:"); scanf("%d", &e.gc); return e; } void guardarEstadistica(Estadistica e, char archivo[]){ FILE *f; f = fopen(archivo, "a"); if (f == NULL){ perror("Se ocasiono un error"); return ; } fprintf(f, "%s\n", e.equipo); fprintf(f, "%d\n", e.jj); fprintf(f, "%d\n", e.jg); fprintf(f, "%d\n", e.je); fprintf(f, "%d\n", e.jp); fprintf(f, "%d\n", e.gf); fprintf(f, "%d\n", e.gc); fclose(f); } void leerArchivo(char archivo[]){ FILE *f; Estadistica e; char linea[1024]; int df, pt; f = fopen(archivo, "r"); if(f == NULL){ perror("No existe el archivo"); return; } printf("Equipo JJ JG JE JP GF GC DF PT\n"); do{ fgets(e.equipo, sizeof(e.equipo), f); //quitar el salto de linea poniendo el character nulo en la posicion anterior e.equipo[strlen(e.equipo)-1]='\0'; if (feof(f)){ break; } //leer en una variable cadena los datos fgets(linea, sizeof(linea), f); Página 6 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI //convertimos la cadena leida en numero (int) e.jj = atoi(linea); fgets(linea, sizeof(linea), f); e.jg = atoi(linea); fgets(linea, sizeof(linea), f); e.je = atoi(linea); fgets(linea, sizeof(linea), f); e.jp = atoi(linea); fgets(linea, sizeof(linea), f); e.gf = atoi(linea); fgets(linea, sizeof(linea), f); e.gc = atoi(linea); df = e.gf – e.gc; pt = e.jg*3 + e.je*1; printf("%-30s %-2d %-2d %-2d %-2d %-2d %-2d %-2d %-2d \n", e.equipo, e.jj, e.jg, e.je, e.jp, e.gf, e.gc, df, pt); }while(1); fclose(f); } Las funciones vistas hasta ahora (fgetc, fputc, fgets, fputs) son adecuadas para trabajar con caracteres (1 byte) y cadenas. Pero, ¿qué sucede cuando se quiere trabajar con otros tipos de datos? Suponga que se quiere almacenar variables de tipo int en un archivo. Como las funciones vistas hasta ahora sólo pueden operar con cadenas se requiere convertir los valores a cadenas (con la función itoa) o utilizar la función fprintf(). Para recuperar luego estos valores se deben leer como cadenas y pasarlos a enteros (atoi). Existe una solución mucho más fácil, utilizar las funciones fread() y fwrite(). Estas funciones permiten tratar con datos de cualquier tipo, incluso con estructuras. En el siguiente ejemplo se utiliza fwrite() y fread() para guardar la estructura de una sola vez y recuperar la información directa. #include <stdio.h> #include <stdlib.h> typedef struct { char nombre[20]; char apellido[20]; int telefono; }Datos; void main() { FILE *archivo; Datos registro; archivo = fopen( "nombres.txt", "a" ); system("clear"); do { printf( "Nombre: " ); gets(registro.nombre); if (strcmp(registro.nombre,"")) { Página 7 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI printf( "Apellido: " ); gets(registro.apellido); printf( "Telefono: " ); scanf(“%d”, registro.telefono); getc(stdin); //se guarda el registro en el archivo, 1 solo registro fwrite( &registro, sizeof(Datos), 1, archivo ); } } while (strcmp(registro.nombre,"")!=0); fclose( archivo ); system("clear"); printf("Contenido del archivo\n"); archivo = fopen( "nombres.txt", "r" ); while (!feof(archivo)) { //se lee un registro si se pudo leer regresara un 1, ya que se instruye que se lea de 1 en 1 if (fread( &registro, sizeof(Datos), 1, archivo )) { printf( "Nombre: %s\n", registro.nombre ); printf( "Apellido: %s\n", registro.apellido); printf( "Telefono: %d\n", registro.telefono); } } fclose( archivo ); } 4. PROCEDIMIENTO (DESCRIPCIÓN) A) EQUIPO NECESARIO MATERIAL DE APOYO Equipo de cómputo con Linux instalado o con conexión a algún servidor de Linux Apuntes B) DESARROLLO DE LA PRÁCTICA Lea cuidadosamente los siguientes planteamientos, identifique las entradas y la salida para presentar una solución en lenguaje C. 1. Utilice el código del primer ejemplo y modifique lo necesario para mostrar al final el número de vocales, el número de dígitos, el número de palabras y el número de líneas contenidas en el texto. 2. Copie, compile y ejecute el programa ejemplo sobre las estadísticas de la Liga de Futbol Mexicano y modifique lo necesario (cambiar código, agregar funciones) para: a) Mostrar ordenada la información de acuerdo a los puntos obtenidos, el líder en la posición 1, etc.., el líder lo determina la mayor cantidad de puntos PT, cuando dos equipos tienen la misma cantidad de puntos el siguiente criterio es la diferencia de goles (DF), la mejor diferencia. b) Mostrar los 3 equipos que están en el fondo de la clasificación. c) Hacer una búsqueda de un equipo en particular para mostrar sus estadísticas. C) CÁLCULOS Preguntas sobre la práctica de forma INDIVIDUAL, que hará el maestro al finalizar la práctica a cada alumno. Página 8 de 9 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI 5. RESULTADOS Y CONCLUSIONES El resultado de las prácticas deberá visualizarse en pantalla. 6. ANEXOS Funciones para la manipulaciones de archivos 7. REFERENCIAS Manual de C. Héctor Tejeda Villela. Hill. 2005 Página 9 de 9