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) 12 Archivos Binarios 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 binarios para el almacenamiento y recuperación de la información de manera directa 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 8 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 8 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 Binarios Un archivo binario es una secuencia de bytes que tienen una correspondencia uno a uno con un dispositivo externo. Así que no tendrá lugar ninguna traducción de caracteres. Además, el número de bytes escritos (leídos) será el mismo que los encontrados en el dispositivo externo. Ejemplos de estos archivos son Fotografías, imágenes, texto con formatos, archivos ejecutables (aplicaciones), etc. Lectura de un archivo binario 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); La función fread() Esta función lee un bloque de un flujo de datos "puntero_archivo". Efectúa la lectura de un arreglo de elementos "cantidad_registros", cada uno de los cuales tiene un tamaño definido por "tamaño_registro". Luego los guarda en el bloque de memoria especificado por "registro". El indicador de posición de byte avanza hasta leer la totalidad de bytes. Si esto es exitoso la cantidad de bytes leídos es (tamaño_registro*cantidad_registros). La función fwrite() Es capaz de escribir hacia un archivo uno o varios registros de la misma longitud almacenados a partir de una dirección de memoria determinada. El valor de retorno es el número de registros escritos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria de donde se obtendrán los datos a escribir, el tamaño de cada registro, el número de registros a escribir y un puntero FILE del archivo al que se hará la escritura. Manejo del desplazamiento sobre el archivo La función fseek() Esta función sitúa el puntero (cursor) de un archivo en una posición deseada, trabaja para modo binario y texto. int fseek(FILE *puntero_archivo, long offset, int origen); puntero_archivo es un puntero a la estructura del archivo. offset es un entero largo que especifica el número de bytes, a partir de la posición de origen, donde se colocará el cursor. origen es un número entero que especifica la posición de origen al cual se le suma el offset. Puede ser: SEEK_SET: El origen es el comienzo del archivo SEEK_CUR:El origen es la posición actual SEEK_END:El origen es el final del archivo Página 3 de 8 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI La función ftell() Esta función regresa la posición actual del puntero (cursor) de un archivo. -1L. Si ocurre un error regresa un long int ftell(FILE *puntero_archivo); El siguiente ejemplo se introduce información para una agenda, cuando se quiere terminar la captura de información se deja en blanco el nombre (ENTER), posterior se abre el archivo y se lee su contenido. #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char nombre[20]; char apellido[20]; int telefono; }Datos; void main() { FILE *archivo; Datos registro; //agregar b en el modo para indicar que se trata de archivos binarios archivo = fopen( "nombres.bin", "ab" ); system("clear"); do { printf( "Nombre: " ); gets(registro.nombre); if (strcmp(registro.nombre,"")) { printf( "Apellido: " ); gets(registro.apellido); printf( "Telefono: " ); gets(registro.telefono); //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.bin", "rb" ); 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: %s\n", registro.telefono); } } fclose( archivo ); } Página 4 de 8 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI El siguiente ejemplo utiliza el archivo binario “nombres.bin” creado en el ejercicio anterior y ordena la información por apellido. #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char nombre[20]; char apellido[20]; int telefono; }Datos; void main() { FILE *archivo; Datos registro, aux; long cuantos; int x, y; //se abre para lectura y escritura archivo = fopen( "nombres.dat", "r+b" ); //se posiciona el cursor 0 bytes a partir del final del archivo fseek(archivo, 0, SEEK_END); //se pide la cantidad de bytes y se divide entre el tamano de la estructura //para saber cuantas estructuras (personas) estan grabadas cuantos = ftell(archivo) / sizeof(Datos); //regresamos al inicio el archivo rewind(archivo); //Metodo de ordenacion for(x = 1; x<cuantos; x++) for(y = 0; y<cuantos-x; y++) { fseek(archivo, sizeof(Datos)*y, SEEK_SET); fread(&registro, sizeof(Datos), 1, archivo); fseek(archivo, sizeof(Datos)*(y+1), SEEK_SET); fread(&aux, sizeof(Datos), 1, archivo); if(strcasecmp(registro.apellido, aux.apellido)>0) { //se graba las estructuras en orden inverso fseek(archivo, sizeof(Datos)*y, SEEK_SET); fwrite(&aux, sizeof(Datos), 1, archivo); fseek(archivo, sizeof(Datos)*(y+1), SEEK_SET); fwrite(&registro, sizeof(Datos), 1, archivo); } } rewind(archivo); system("clear"); printf("Contenido del archivo\n"); while (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 ); } Página 5 de 8 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI El siguiente ejemplo utiliza el archivo binario “nombres.bin” creado en el primer ejercicio y elimina un registro buscando por apellido. #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char nombre[20]; char apellido[20]; int telefono; }Datos; void main() { FILE *archivo, *archivoaux; Datos registro; char apellbus[20]; int eliminado = 0; //se abre para lectura archivo = fopen("nombres.dat", "rb"); //se crea un archivo auxiliar archivoaux = fopen ("temporal.dat", "wb"); system("clear"); printf("Apellido de la persona a eliminar: "); gets(apellbus); while (fread(&registro, sizeof(Datos), 1, archivo )) if(strcasecmp(apellbus,registro.apellido)==0) { printf("Registro de persona con apellido %s eliminado\n", registro.apellido); eliminado = 1; } else { //se envia la informacion que no se quiere eliminar a un archivo auxiliar fwrite(&registro, sizeof(Datos), 1, archivoaux); } fclose(archivo); fclose(archivoaux); //si hubo eliminados se renombra el archivo auxiliar si no solo se elimina if (eliminado) { remove("nombres.dat"); rename("temporal.dat", "nombres.dat"); } else { remove("temporal.dat"); printf("No existe %s en el archivo\n", apellbus); } getchar(); system("clear"); printf("Contenido del archivo\n"); archivo = fopen("nombres.dat", "rb"); while (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 ); } Página 6 de 8 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI 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 de los ejemplos mostrados en la práctica y construya una aplicación llamada agenda, en la cual se almacenaran también el correo electrónico, el teléfono de casa, del trabajo y el móvil y un grupo(amigos, familiares, otros), de acuerdo al grupo estarán . Construir un menú con las siguientes opciones: a) Alta de contacto b) Baja de contacto c) Consultar 1. Toda la agenda 2. Solo un contacto (por apellido paterno) 3. Regresar d) Ordenar (si dos apellidos coinciden se tomara en cuenta el nombre para ordenar) e) Salir. C) CÁLCULOS Preguntas sobre la práctica de forma INDIVIDUAL, que hará el maestro al finalizar la práctica a cada alumno. 5. RESULTADOS Y CONCLUSIONES El resultado de las prácticas deberá visualizarse en pantalla. 6. ANEXOS Modos de apertura de archivos Página 7 de 8 UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE INGENIERÍA MEXICALI Funciones para la manipulaciones de archivos 7. REFERENCIAS Manual de C. Héctor Tejeda Villela. Hill. 2005 Página 8 de 8