Tema 10 Archivos de datos Fundamentos de Informática Índice • Introducción • Operaciones básicas con archivos • Tipos de Archivos • Archivos de texto • Archivos binarios Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 2 1 • Introducción Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 3 Archivos Un archivo es un conjunto de información que se almacena en un ordenador y puede ser identificado por su ruta completa, cuyo fin ultimo es guardar o proporcionar información. Utilizaremos archivos secuenciales. La memoria RAM se borra en cuanto se corta la corriente. Es necesario un sistema de almacenamiento secundario. Los archivos se almacenan en dispositivos de almacenamiento como el disco duro, diskette, CD ROM, … El manejo de los sistemas de almacenamiento de los archivos es gestionado por el sistema operativo. Carpetas Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Archivos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 4 Archivos • Hasta ahora los programas han tomado y devuelto datos de: • teclado ‐ pantalla. • Una operación de lectura de un fichero es parecida a una operación de lectura de datos desde el teclado • Una operación de escritura de un fichero es parecida a una operación de escritura en pantalla. • Utilizaremos archivos secuenciales. • Operaciones con archivos: – Apertura de archivos: fopen() – Cierre de archivos: fclose() – Lectura de archivos: fprintf() – Escritura en archivos: fscanf() Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 5 2 Operaciones básicas con archivos Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 6 Operaciones básicas con archivos • Diferencias con el manejo de pantalla y teclado: – Es necesario establecer un área de buffer. • Este área almacena la información mientras se está transfiriendo hacia o desde el fichero. – Para apuntar a esa área de buffer se utiliza la siguiente declaración: FILE *punt_fichero; – Donde: • FILE es un tipo especial de estructura que establece el área del buffer. Contiene toda la información que necesitan el resto de funciones que trabajan con archivos, como el modo del archivo, los buffers del archivo, errores ... – Incluida en stdio.h • punt_fichero es una variable de tipo puntero que apunta al comienzo del área del buffer. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 7 Operaciones básicas con archivos • Apertura de un archivo: fopen() – Siempre antes de realizar cualquier operación con un fichero. • Una vez abierto el fichero, y hasta que éste se cierre, se pueden realizar tantas operaciones como se deseen sin necesidad de volver a abrirlo. – El objetivo de abrir un fichero es: • Asociar el nombre del archivo “físico” con el área del buffer. • Especificar el uso que se le va a dar al fichero (lectura, escritura, lectura‐escritura, en modo texto, binario ...). Memoria Externa Memoria Interna Canal físico Programa Buffer Canal lógico Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 8 Registro buffer: espacio de memoria interna que reserva el sistema para el intercambio de registros entre el archivo y el programa. Escuela Técnica Superior de Ingeniería ICAI Operaciones básicas con archivos • Apertura de un archivo: fopen() – Prototipo de la función: FILE *fopen (char * nombre_completo_archivo, char *modo); • nombre_completo_archivo (cadena de caracteres): es el nombre del archivo físico sobre el que queremos trabajar. – Incluyendo el camino completo y la unidad en caso de que fuera necesario. • modo (cadena de caracteres): indica el uso que vamos a hacer del fichero o archivo (ver la siguiente transparencia) • El valor de retorno de fopen(): – Éxito: El puntero al comienzo del área del buffer. – Fracaso: devuelve NULL si no se pudiera abrir el fichero. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 9 Operaciones básicas con archivos • Apertura de un archivo: Modo – “r” » Abre un archivo existente solo para lectura. – “w” » Abre un nuevo archivo solo para escritura. En caso de existir un archivo con ese nombre, lo borra y crea un nuevo archivo vacío. – “a” » Abre un archivo para añadir. Si el archivo no existe crea uno nuevo, pero si existe no borra su contenido. Se posiciona al final del archivo de forma que sucesivas escrituras se añaden al final del archivo original. – “r+” » Abre un archivo existente para actualizarlo (tanto para lectura como para escritura). – “w+” » Abre un archivo nuevo para lectura y escritura. Si existiera un archivo con ese nombre, lo borra y crea un nuevo archivo vacío. – “a+” » Abre un archivo existente para leer y añadir. Si no existiera el archivo se creará uno nuevo. – ‘b’ » Hay que añadirle a cualquiera de los modos anteriores cuando se esté trabajando con datos binarios. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 10 Operaciones básicas con archivos Ejemplo Función fopen(). Apertura para leer y escribir. #include <stdio.h> ... int main(void){ FILE *pfich; ... pfich=fopen(“c:\\temp\\pepe.txt”,“r+”);/*Apertura*/ if(pfich==NULL){ /*Comprobamos apertura*/ printf(“Error: No se puede abrir el archivo.\n”); }else{ ... } return 0; } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 11 Operaciones básicas con archivos • Cierre de un archivo: fclose() – Su objetivo es liberar el espacio del área del buffer. – Se escriben a disco todos los datos que aún queden en el buffer, se “desconecta” el archivo del programa y se libera el puntero al archivo. – Es obligatorio cerrar un fichero cuando se haya terminado con su uso dentro del programa. – Siempre que queramos cambiar la forma de acceso al fichero, también será necesario cerrarlo y volverlo a abrir especificando el nuevo tipo de acceso para el manejo del fichero. • Un fichero no puede abrirse mas de una vez sin antes haberlo cerrado. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 12 Operaciones básicas con archivos • Cierre de un archivo: fclose() – Prototipo de la función: int fclose(FILE *puntero_al_archivo); • puntero_al_archivo: es el puntero a archivo devuelto por la función fopen() al abrir el archivo que se desea cerrar. • El valor devuelto por la función es: 0: si el archivo se cerró con éxito, ‐1: si ocurrió algún tipo de error al cerrarlo Independientemente del valor de retorno, el archivo se cierra. Un error típico es que el disco se ha llenado y no se ha podido vaciar el buffer con la consiguiente pérdida de datos Ejemplo Función fclose(). Cierre fichero “pepe.txt” ejemplo anterior. if(fclose(pfich)!=0){ printf(“Error al cerrar el archivo\n”); printf(“Posible pérdida de datos”); } Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos Escuela Técnica Superior de Ingeniería ICAI 13 Operaciones básicas con archivos #include <stdio.h> int main(void) { FILE *pfich; Declaración de un puntero a archivo pfich = fopen(“datos.txt”,”w”); Apertura en modo escritura (w) del archivo “datos.txt” Comprobación de que la if (pfich == NULL) { apertura ha sido correcta printf(“\n Error al abrir el fichero”); }else{ ... /* Se utiliza el archivo para escritura */ /* Al acabar de usar el archivo */ Cierre del archivo y comprobación de si se ha realizado correctamente if (fclose(pfich) != 0) { printf(”\n Error al cerrar el archivo “); } } } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 14 3 Tipos de archivos Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 15 Tipos de archivos • Tipos de archivo: – Texto. • Archivos ASCII planos, obtenidos y manejados desde programa utilizando cadenas de caracteres. • Se pueden ver con un editor de texto. – Binario. • Archivos con los datos guardados como copia exacta de la memoria del ordenador (binario). • Sólo comprensible desde un programa que “sepa” qué tipos de datos contiene el archivo y de qué forma están guardados. • Si se visualizan con un editor de texto no son comprensibles. • Los archivos binarios y los programa que utilizan archivos binarios no son fácilmente portables a otros ordenadores y otros compiladores (el tamaño de las variables puede variar). • Los archivos de texto son legibles y fáciles de portar, pero ocupan más espacio para almacenar la información. • Los archivos binarios no son legibles con un editor de texto y no son portables de un ordenador a otro, pero ocupan menos espacio • Ejemplo: variable entera de valor 2563 (texto: 4 bytes; binario: 2 bytes). Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 16 Tipos de archivos • Creación de un archivo: – Un archivo secuencial debe ser creado antes de ser procesado. – Formas de crear un archivo: Directamente: Mediante el uso de un editor de texto (archivos de texto). • Indirectamente: Mediante un programa que reciba información, la procese y la guarde en un archivo (texto o binario). • • La lectura y escritura de archivos varía según el tipo de archivos: – Texto: fprintf, fscanf, getc, putc, fgets, fputs – Binarios: fwrite, fread, fseek Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 17 4 Archivos de texto Archivos de Texto • • Son los archivos que contienen caracteres ASCII. Apertura y cierre de fichero. – • Según lo visto en las transparencias anteriores. Los archivos guardan cadenas de caracteres: Es posible utilizar las funciones de biblioteca utilizadas para escribir o leer cadenas vistas a lo largo del curso. – La diferencia está en que ahora cuando se utilicen estas funciones hay que incluir el puntero al buffer del fichero • putc(caracter,puntero) • getc(puntero) • fputs(cadena,puntero) • fgets(cadena,numero de caracteres,puntero) • fprintf(puntero,cadena de control,variables) • fscanf(puntero, cadena de control,variables) – Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 19 Archivos de Texto • Las funciones fprintf() y fscanf(): – • Las propias funciones se encargan de realizar las conversiones de formato que son necesarias para poder transformar los valores binarios usados internamente en el ordenador a cadenas de caracteres usadas en los archivos de texto. fprintf(): – – El funcionamiento es idéntico al de printf() salvo que ahora es necesario indicar en qué archivo ha de escribir. Valor de retorno: • Éxito: devuelve el número de bytes que ha escrito • Fracaso: devuelve EOF fprintf (FILE *puntero_al_archivo, const char *cadena_de_formato,...); Ejemplo ... Función fprintf(). Escritura en el fichero “pepe.txt”. /*Apertura realizada*/ fprintf(pfich,”El valor de %d en hexadecimal es %x\n”,15,15); Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 20 Archivos de Texto • fscanf(): – – El funcionamiento es idéntico al de scanf() salvo que ahora es necesario indicar en qué archivo ha de leer. Valor de retorno (cuando sólo se lee un valor): • • • – Éxito: devuelve el valor 1 si ha leído correctamente Fracaso: devuelve 0 si ha ocurrido un error en la lectura por una mala especificación de formato. EOF: si no se ha leído nada porque se ha llegado al final del archivo. Valor de retorno (cuando sólo se lee más de un valor): • • • El valor devuelto es igual al número de datos leídos si se ha leído correctamente.(devuelve el número de argumentos que han sido leídos y a los que se le ha asignado un valor.) Si se ha producido algún error antes de leer todos los datos el valor devuelto es igual al número de datos leídos correctamente. EOF: si no se ha leído nada porque se ha llegado al final del archivo. int fscanf (FILE *puntero_al_archivo, const char *cadena_de_formato,...); Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 21 Archivos de Texto /* Programa: Lee el archivo "pepe" que contiene números en punto flotante y calcula su suma. */ #include <stdio.h> int main(void) { int n; /* Valor devuelto por fscanf */ FILE *pfich; /* Puntero al archivo */ double dato; /* dato leído del fichero */ double sum_tot; /* Suma de los datos */ pfich = fopen("pepe.txt", "r+"); if (pfich == NULL){ printf("Error: No se puede abrir el fichero \"pepe\"\n"); }else{ •Si el archivo pepe.txt contiene: 1.3 3.4 4.5 123.4 • El resultado sería: El valor de la suma es: 132.600000 sum_tot = 0; /* Inicialización de la suma antes de entrar en el bucle*/ n = fscanf(pfich, “ %lf ", &dato); while (n != EOF && n != 0) { /* termina en cuanto ocurra un error de lectura*/ sum_tot+=dato; n = fscanf(pfich, “ %lf ", &dato); } printf("El valor de la suma es: %lf\n", sum_tot); if( fclose(pfich) != 0){ printf("Error al cerrar el fichero\n"); } } return 0; } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 22 8.- Archivos de texto Ejemplo Manejo de archivos. Diseñar un programa que escriba en el fichero “c:\temp\pepe.txt” los números 1.3, 3.4, 4.5 y 123.4 en líneas separadas y cierre el fichero. A continuación es programa abrirá el fichero para lectura, leerá todos los datos introducidos anteriormente, los sumará e imprimirá la suma. #include <stdio.h> #include <stdlib.h> int main(void) {int n; FILE *fichero; double dato; double sum_tot; /*Valor devuelto por fscanf*/ /*Puntero al archivo*/ /*Dato leído del fichero*/ /*Suma de los datos*/ /*Abrimos el fichero para introducir datos*/ fichero=fopen("c:\\temp\\pepe.txt", "w"); if(fichero==NULL) printf("Error de apertura"); else {fprintf(fichero,"1.3\n3.4\n4.5\n123.4"); 1 2 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 23 8.- Archivos de texto 1 2 /*Cerramos el fichero*/ if(fclose(fichero)!=0) {printf("Error al cerrar le fichero\n"); } } /*Abrimos el fichero para leer datos*/ fichero=fopen("c:\\temp\\pepe.txt", "r"); if(fichero==NULL) printf("Error de apertura"); else {sum_tot=0.0; n=fscanf(fichero,"%lf",&dato); while(n!=1) {sum_tot=sum_tot+dato; n=fscanf(fichero,"%lf",&dato); } 1 3 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 24 8.- Archivos de texto 1 3 /*Imprimimos la suma*/ printf(" El valor de la suma es : %lf\n",sum_tot); /*Cerramos el fichero*/ if(fclose(fichero)!=0) {printf("Error al cerrar el fichero\n"); } } } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 25 Archivos de Texto • Las funciónes fgets(), fputs(), getc() ó fgetc(), putc() ó fputc() – – • Son funciones que escriben o leen un carácter (fgetc(), getc(), fputc(), putc()) o cadenas de caracteres (fgets(), fputs()) No realizan conversión de formatos (todo se hace con caracteres) Lectura de un carácter: int fgetc(FILE *puntero_a_archivo) ó int getc(FILE *puntero_a_archivo) – – Leen el siguiente carácter del archivo. Valor de retorno: • • • Éxito: el carácter leído Fracaso: Si llega al final de fichero u ocurre un error, el valor de retorno es EOF. Escritura de un carácter: int fputc(int car, FILE * puntero_a_archivo) ó int putc(int car, FILE * puntero_a_archivo) – – Escriben el carácter car en el archivo al que apunta puntero_a_archivo. Valor de retorno: • • Éxito: el propio carácter escrito Error: EOF Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 26 Archivos de Texto #include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(void) { FILE *punt; char c; punt=fopen("datos.txt","w"); if (punt==NULL) { printf("\n Error – NO SE PUEDE ABRIR EL FICHERO"); } else { do { c = toupper(getchar()); putc(c, punt); }while (c != '\n'); if (fclose(punt) != 0) { printf("Error al cerrar el fichero"); } } return 0; } Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos Escuela Técnica Superior de Ingeniería ICAI 27 Cadena de caracteres: fgets(), fputs() • Lectura de una cadena de caracteres: char * fgets(char *cadena, int tam_cad, FILE *punt_a_arch) La cadena leída se almacena en esta variable – Valor de retorno: • • • Al final de la cadena siempre se añade el ‘\0’ La lectura termina cuando: - Encuentra el \n (que sí se copia) - Encuentra el fin de fich (no se escribe \n) - Se han leído (tam_cad-1) caracteres Éxito: es un puntero a la cadena leída. Fracaso: NULL, si se llega al final de fichero u ocurre un error Escritura de una cadena de caracteres: int fputs(const char *cadena, FILE *punt_a_arch) – Valor de retorno: • • Escribe la cadena en el archivo al que apunta punt_a_arch SIN EL ‘\0’ DEL FINAL Éxito: número positivo si se ha escrito la cadena correctamente Error: EOF Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 28 Archivos de Texto • Lectura de una cadena de caracteres: char * fgets(char *cadena, int tam_cad, FILE *puntero_a_archivo). – – – Lee una cadena de caracteres del archivo apuntado por puntero_a_archivo y la almacena en cadena. La lectura se acaba cuando se encuentra el carácter ‘\n’ (que SÍ se escribe en la cadena), cuando se encuentra el fin de fichero (en este caso no se escribe ‘\n’ en la cadena) o cuando se han leído tam_cad‐1 caracteres. En todos estos casos, se escribe un carácter ‘\0’ en la cadena a continuación del último carácter leído. Valor de retorno: • • • Éxito: es un puntero a la cadena leída. Fracaso: NULL, si se llega al final de fichero u ocurre un error Escritura de una cadena de caracteres: int fputs(const char *cadena, FILE *puntero_a_archivo) – – Escribe la cadena en el archivo al que apunta puntero_a_archivo SIN EL ‘\0’ DEL FINAL. Valor de retorno: • • Éxito: número positivo si se ha escrito la cadena correctamente Error: EOF Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 29 Archivos de Texto Ejemplo 1: OPCION A, lectura de una cadena del teclado, escritura en un archivo y lectura de esa cadena del archivo #include <stdio.h> #include <ctype.h> int main(void) { FILE *punt; char cadena[80]; char cadena2[80]; punt=fopen("a:\\datos.txt","r"); if (punt==NULL){ printf("\nerror - NO SE PUEDE ABRIR EL FICH "); }else{ fgets(cadena2,80,punt); punt=fopen("a:\\datos.txt","w"); if (punt==NULL) { printf("\n Error - NO SE PUEDE ABRIR EL FICHERO PARA ESCRIBIR"); }else{ puts("\nIntroduzca una cadena de caracteres:\n"); gets(cadena); fputs(cadena,punt); if (fclose(punt) != 0) { printf(“Error cerrando el archivo “); } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI if (fclose(punt) != 0) { printf(“Error al cerrar el archivo”); } puts("\nYa hemos leido el fichero y contiene:\n"); puts(cadena2); } } } Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 30 Archivos de Texto Ejemplo 1: OPCION B, lectura de una cadena del teclado, escritura en un archivo y lectura de esa cadena del archivo #include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(void) { FILE *punt; char cadena[80]; char cadena2[80]; fgets(cadena2,80,punt); if (fclose(punt) != 0) { printf(“Error al cerrar el archivo”); } punt=fopen("datos.txt","w+"); if (punt==NULL) { printf("\n Error - NO SE PUEDE ABRIR EL FICHERO PARA ESCRIBIR"); }else{ puts("\nYa hemos leido el fichero contiene:\n"); puts(cadena2); } } puts("\nIntroduzca una cadena de caracteres:\n"); gets(cadena); fputs(cadena,punt); /* Es necesario volver a apuntar al principio del archivo con el puntero */ rewind(punt); Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI ATENCIÓN Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 31 Archivos de Texto if (fclose(punt) != 0) { printf(“Error al cerrar el fichero “); } #include <stdio.h> #include <ctype.h> #define TAM 80 int main(void) { FILE *punt; char cadena[TAM]; char cadena2[TAM]; char nombre_archivo[TAM]; int n; } punt=fopen(nombre_archivo,"r"); if (punt == NULL) { printf("\n Error - NO SE PUEDE ABRIR EL FICHERO” “ PARA ESCRIBIR"); }else{ puts("\nYa hemos leido el fichero y contiene:\n"); n = fscanf(punt,"%[^\n]\n",cadena2); if (n == EOF || n == 0) { printf(“Error al leer la cadena 2”); }else{ puts(cadena2); if (fclose(punt) != 0) { printf(“Error al cerrar el fichero “); } } } printf(“Introduzca el nombre del archivo”); gets(nombre_archivo); punt=fopen(nombre_archivo,"w"); if (punt == NULL) { printf("\n Error - NO SE PUEDE ABRIR EL” “ FICHERO PARA ESCRIBIR"); }else{ puts("\nIntroduzca una cadena de caracteres:\n"); gets(cadena); fprintf(punt,"%s\n",cadena); Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI } Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 32 Archivos de Texto Ejemplo: Almacenamiento de estructuras en archivos de texto #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 2 /* Dimensión de los vectores (número de productos) */ / * Declaración de una estructura para los productos */ typedef struct { char nombre[12]; int precio; }PROD; Resultado: archivo datos.txt (35 caracteres) CD Rosana 2563 CD Titanic 2628 /*** Creo el archivo ***/ int main(void) f = fopen("datos.txt","w"); { if (f ==NULL) { PROD producto[N]; /* Vector de productos en el almacén */ printf("Error al crear el archivo datos.txt\n"); int i; /* contador para los bucles*/ }else{ FILE *f; /* Descriptor del archivo de texto */ for (i = 0; i<N; i++) { fprintf(f,"%s\n",producto[i].nombre); /*** Inicializo del vector ***/ fprintf(f,"%6d\n",producto[i].precio); strcpy(producto[0].nombre,"CD Rosana"); } producto[0].precio=2563; fclose(f); strcpy(producto[1].nombre,"CD Titanic"); } producto[1].precio=2628; } Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 33 Escuela Técnica Superior de Ingeniería ICAI Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 34 • • • • • • Ejemplo Escribir un programa que calcule las pérdidas que tendría un almacén si explotase (es decir, perdiera todos los productos que tiene en el almacén). La información almacenada de cada producto es: – Nombre del producto – Número de unidades de ese producto en el almacén – Precio unitario Por lo tanto, para poder guardar la información de cada producto, será necesario crearse un tipo de estructura T_PRODUCTO con los campos anteriormente citados. La información de todos los productos existentes en el almacén está contenida en un fichero de texto llamado “almacen.txt” y que deberá crearse el alumno (se puedo utilizar el ejemplo proporcionado por el profesor en este enunciado) en un editor de texto ASCII (el editor del MinGW es ASCII) para poderlo leer desde su programa. En el programa principal se debe declarar un vector estático de estructuras T_PRODUCTO para almacenar posteriormente la información de todos los productos del almacén (asignación estática de memoria). Para saber el número de productos diferentes que hay en el almacén, se ha de abrir el fichero y leer el primer campo, que contiene dicha información. El fichero de texto tiene la información de todos los productos a continuación del número de productos diferentes, por lo que será necesario ir leyendo el fichero y rellenando el vector de estructuras de tipo T_PRODUCTO. Una vez finalizada la lectura del fichero de texto, será necesario cerrar dicho fichero. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 35 Ejemplo Un ejemplo de este fichero de entrada sería: 3 mechas 12 40 detonadores 23 456 dinamita 23 100 mecheros 4 100 • Una vez finalizada la lectura de todos los productos se le debe mostrar al usuario la lista de los productos existentes en el almacén utilizando la función MostrarAlmacen(). • Para calcular cuál sería la pérdida total al destruirse el almacén, se ha de utilizar la función PerdidaTotal() que devuelve la pérdida total, y que tendrá el siguiente prototipo: double PerdidaTotal(T_PRODUCTO *tabla, int num_productos); • Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 36 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 37 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 38 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 39 4 Archivos Binarios Archivos binarios • • • • • • Los archivos binarios se utilizan para almacenar la información como una copia exacta de la memoria del ordenador. Normalmente, no se pueden ver con un editor de texto, pues sería una casualidad que los bytes que contienen fuesen caracteres legibles. Útil cuando se desea guardar en un archivo bloques de información Permite escribir los bloques de una sola vez sin necesidad de escribir cada uno de sus componentes. Problema de portabilidad Permiten el acceso directo a los datos en el archivo En estos casos utilizaremos las funciones fwrite() y fread(): – – Ambas funciones hacen un acceso directo a la memoria del ordenador a partir de la dirección de estructura. Escritura: size_t fwrite(void *estructura, size_t tam, size_t numero, FILE *archivo); • – Toma un número (tam* numero) de bytes de la memoria a partir de la dirección estructura y los escribe en el archivo. Lectura: size_t fread (void *estructura, size_t tam, size_t numero, FILE *archivo); • Lee del archivo un número (tam* numero) de bytes y los guarda a partir de la dirección de memoria estructura. Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 41 Función fread() – Ejemplo 1 // Programa que lee todos los registros en el fichero items.dat // y muestra el contenido en la pantalla // El número de registros no se conoce de antemano #include <stdio.h> #include <stdlib.h> typedef struct{ char nombre[20]; int existencias; float precio_unitario; }T_ITEM; En el ejemplo tenemos en cuenta que fread() devuelve el número de elementos leídos del archivo. Si se leen menos elementos de los pedidos en la llamada o bien ha ocurrido un error, o bien se han alcanzado el fin del fichero. En este caso sólo se lee un elemento y, por lo tanto, el bucle while continúa leyendo nuevos registros hasta que el valor devuelto por fread() sea distinto de 1. int main() { FILE *p_fich; T_ITEM item; if((p_fich = fopen ("items.dat", "rb"))==NULL) { printf("ERROR. No se puede abrir el fichero para lectura\n"); } else { while(fread(&item, sizeof(T_ITEM), 1, p_fich) == 1) { printf("\nNombre del item => %s\n", item.nombre); printf("Existencias => %d\n", item.existencias); printf("Precio unitario => %.2f\n", item.precio_unitario); } fclose(p_fich); } return 0; Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos Escuela Técnica Superior de Ingeniería ICAI } 42 42 Función fread() – Ejemplo 2 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fp; int i; double bal[5] = {1.1, 2.2, 3.3, 4.4, 5.5}; fp=fopen("test.dat", "wb+"); if (fp==NULL) { printf("\nNo se puede abrir el fichero\n"); } else { fwrite(bal, sizeof(double), 5, fp); rewind(fp); if(fread(bal, sizeof(double), 5, fp)!=5) { printf("\nError al leer el fichero\n"); } else { for(i=0; i<5; i++) printf("%.2f ", bal[i]); fclose(fp); } } return 0; El programa escribe cinco números de tipo double del vector bal a un fichero de disco llamado test y, a continuación, se leen del disco. El valor que devuelve fread() —5 en este caso— se usa para comprobar el resultado de la operación de lectura. En el ejemplo se quiere constatar que fread() puede retornar valores diferentes a 1. } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 43 43 Archivos binario Ejemplo: Almacenamiento de estructuras en archivos de binarios #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 2 // Dimensión de los vec. (núm de productos) /* Declaración de una estructura para los productos */ typedef struct { char nombre[12]; int precio; }T_PROD; int main(void) { T_PROD producto[N]; /* Vector de productos */ int i; /* contador para los bucles*/ FILE *f; /* Descriptor del archivo de texto */ Resultado: no se puede ver pero ocupa 28 caracteres (ya que cada estructura ocupa 14 bytes) Apertura en modo binario /*** Creo el archivo ***/ f=fopen("datos.dat","wb"); if (f==NULL) { printf("Error al crear el archivo datos.dat\n"); Tamaño de la estructura }else{ /*** Inicializo del vector ***/ strcpy(producto[0].nombre,"CD Rosana"); producto[0].precio=2563; strcpy(producto[1].nombre,"CD Titanic"); producto[1].precio=2628; } for (i=0; i<N; i++) { fwrite (&producto[i] , sizeof(producto[i]) ,1, f); } fclose(f); Dirección de la estructura a escribir } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 44 Archivos binarios #include <stdio.h> #include <stdlib.h> typedef char T_Cadena30[30]; typedef struct{ T_Cadena30 nombre; int edad; }T_Ficha; int main(void) { FILE *punt; T_Ficha ficha; T_Ficha ficha2; punt=fopen("a:\\datos.dat","wb"); if (punt==NULL) { printf("\n Error al abrir el fichero "); }else{ printf("Introduzca el nombre de la persona:\n"); gets(ficha.nombre); printf("Introduzca la edad de la persona:\n"); scanf("%d",&ficha.edad); fwrite(&ficha, sizeof(T_Ficha), 1, punt); punt=fopen("a:\\datos.dat","rb"); if (punt==NULL) { printf("\n Error al abrir el fichero "); }else{ puts("\nYa hemos leido el fichero y contiene:\n"); fread(&ficha2, sizeof(T_Ficha), 1 , punt); printf("NOMBRE: "); puts(ficha2.nombre); printf("EDAD: "); printf("%d",ficha2.edad); if (fclose(punt) != 0) { printf(“Error al cerrar el fichero “); } } } if (fclose(punt) != 0) { printf(“Error al cerrar el fichero “); } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 45 Ejemplo Opción 1 Archivos binarios #include <stdio.h> #include <stdlib.h> #define N 5 typedef struct{ char nombre[30]; int edad; }T_Ficha; int main(void) { Lectura de una FILE *punt; estructura cada vez T_Ficha ficha; T_Ficha lista[N]; int cont; punt=fopen(“prueba.dat","wb"); if (punt==NULL) { printf("\n Error abriendo el fichero "); }else{ for (cont=0;cont<N;cont++) { fflush(stdin); printf("Introduzca el nombre:\n"); gets(ficha.nombre); printf("Introduzca la edad :\n"); scanf("%d",&ficha.edad); fwrite(&ficha, sizeof(T_Ficha), 1, punt); } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI if (fclose(punt) != 0 ) { printf(“Error al cerrar el archivo”); } } punt=fopen("prueba.dat ","rb"); if (punt==NULL) { printf("\n Error abriendo el fichero "); }else{ puts("\nYa hemos leido el fichero y contiene:\n"); for (cont=0;cont<N;cont++) { fread(&lista[cont], sizeof(T_Ficha),1,punt); printf("NOMBRE: "); puts(lista[cont].nombre); printf("EDAD: "); printf("%d\n",lista[cont].edad); } if (fclose(punt) != 0 ) { printf(“Error al cerrar el archivo”); } } } Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 46 Archivos binarios Ejemplo Opción 2 #include <stdio.h> If (fclose(punt) != 0 ) { printf(“Error al cerrar el archivo”); #include <stdlib.h> } #define N 5 } punt=fopen("prueba.dat","rb"); de las N typedef struct{ Lectura if (punt==NULL) { estructuras a la vez printf("\n Error abriendo el fichero "); char nombre[30]; } else{ int edad; fread(lista, sizeof(T_Ficha),N ,punt); }T_Ficha; puts("\nYa hemos leido el fichero y contiene:\n"); int main(void) for (cont = 0; cont < N; cont++) { printf("NOMBRE: "); { puts(lista[cont].nombre); FILE *punt; printf("EDAD: "); printf("%d\n",lista[cont].edad); T_Ficha ficha; } T_Ficha lista[N]; If (fclose(punt) != 0 ) { int cont; printf(“Error al cerrar el archivo”); } punt=fopen(“prueba.dat","w } b"); } Departamento de Sistemas Informáticos if (punt==NULL) {Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 47 Escuela Técnica Superior de Ingeniería ICAI i f("\ E bi d Archivos binarios Permiten el acceso directo a los datos en el archivo utilizando la función fseek(). • Prototipo: size_t fseek(FILE *archivo, long posicion, int origen); • – – – archivo : • Puntero al buffer del fichero con el que estamos trabajando. posicion : • Desplazamiento en bytes a partir de lo que indique origen origen : • Especifica donde comienza la búsqueda. – – – • SEEK_CUR: Posición actual del puntero. SEEK_END: Final del fichero. SEEK_SET: Comienzo del fichero Valor de retorno: – – Éxito: devuelve 0 (cuando el puntero del archivo se ha movido satisfactoriamente) Fracaso: devuelve un valor distinto de 0 Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 48 48 Archivos binarios • Ejemplos: fseek(fp,0,SEEK_SET); /* Va a la primera posición del archivo */ fseek(fp,10*sizeof(producto[0]),SEEK_SET); /* Va al 11º producto */ fseek(fp,2*sizeof(producto[0]),SEEK_CUR); /* Me salto dos productos */ Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 49 49 fseek(): Un ejemplo sencillo typedef struct { char nombre[40]; char calle [30]; char ciudad[30]; char provincia[20]; int cod_postal; }T_INFO; La siguiente función busca la estructura especificada de tipo T_INFO void Buscar(int num_cliente) { FILE *fp; T_INFO info; if((fp=fopen("correo.dat", "rb"))==NULL) { printf("No se puede abrir el fichero.\n"); } else { // Buscar la estructura escogida fseek(fp, num_cliente*sizeof(T_INFO), SEEK_SET); // Leer la información a memoria fread(&info, sizeof(T_INFO), 1, fp); fclose(fp); } } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 50 50 Archivos binarios: ejemplo fseek() #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct{ char nombre[30]; int edad; }T_Ficha; typedef T_Ficha T_Lista[10]; void introducir_datos(T_Lista lista); void pinta_datos(T_Lista lista); void guardar_fichero(T_Lista lista); void cargar_fichero(T_Lista lista); void modificar(void); int main(void) { T_Lista lista,lista2; introducir_datos(lista); guardar_fichero(lista); modificar(); cargar_fichero(lista2); pinta_datos(lista2); } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI void introducir_datos(T_Lista lista) { int cont; printf("Introduzca los nombres y edades de 5 personas: \n"); for (cont=0;cont<5;cont++) { fflush(stdin); printf("Introduzca el nombre de la persona:\n"); gets(lista[cont].nombre); printf("Introduzca la edad de la persona:\n"); scanf("%d",&lista[cont].edad); } } void pinta_datos(T_Lista lista) { int cont; printf("\n:::::Los datos del fichero leido son:\n"); for (cont=0;cont<5;cont++) { printf("NOMBRE: "); puts(lista[cont].nombre); printf("EDAD: "); printf("%d\n",lista[cont].edad); } } Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 51 1/4 Archivos binarios: ejemplo fseek() void guardar_fichero(T_Lista lista) { FILE *punt; int cont; printf("\nGUARDANDO FICHERO....\n"); punt=fopen("a:datos.dat","wb"); if (punt==NULL) { printf("\nERROR"); }else{ void cargar_fichero(T_Lista lista) { FILE *punt; int cont=0; printf("\nLEYENDO FICHERO.................\n"); punt=fopen("a:datos.dat","rb"); if (punt==NULL) { printf("\n Error al abrir el fichero"); }else{ while ( fread(&lista[cont],sizeof(T_Ficha),1,punt)) == 1) { cont++; } for(cont=0;cont<5;cont++) { fwrite(&lista[cont],sizeof(T_Ficha),1,punt); } if (fclose(punt) != 0) { printf(“Error cerrando el fichero “); } printf("\n:::::FICHERO LEIDO:::::\n"); /* Otra opción en vez del bucle anterior fwrite(lista,sizeof(T_Ficha),5,punt); */ if (fclose(punt) != 0) { printf(“Error al cerrar el archivo”); } printf("\n:::::FICHERO GUARDADO:::::\n"); } } } } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI 2/4 Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 52 Archivos binarios: ejemplo fseek() 3/4 void modificar(void) { FILE *punt; T_Ficha registro; int cont=0; T_Cadena30 cadena; fflush(stdin); printf("\nIntroduzca nombre a buscar:\n"); gets(cadena); printf("\nLEYENDO FICHERO Y BUSCANDO NOMBRE SOLICITADO..............\n"); punt=fopen("a:datos.dat","rb+"); if (punt==NULL) { printf("\nERROR"); }else{ do { fread(&registro,sizeof(T_Ficha),1,punt); cont++; } while ((strcmp(registro.nombre,cadena)!=0)&&(cont<5)); CONTINUA EN SIGUIENTE TRANSP....... Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 53 Archivos binarios: ejemplo fseek() if (strcmp(registro.nombre,cadena)==0) { printf("\n..........INDIVIDUO ENCONTRADO..........\n"); printf("\n...DATOS ACTUALES:\n"); printf("NOMBRE: %s\n",registro.nombre); printf("EDAD: %d\n",registro.edad); printf("\n:::::INTRODUZCA NUEVOS DATOS:::::::::\n"); fflush(stdin); printf("Introduzca el nombre de la persona:\n"); gets(registro.nombre); printf("Introduzca la edad de la persona:\n"); scanf("%d",&registro.edad); printf("\n..........MODIFICANDO LOS DATOS EN EL FICHERO..........\n"); fseek(punt,(cont-1)*sizeof(T_Ficha),SEEK_SET); fwrite(&registro,sizeof(T_Ficha),1,punt); printf("\n..........DATOS MODIFICADOS EN EL FICHERO..........\n"); } else { printf("\n::::EL NOMBRE SOLICITADO NO SE ENCUENTRA EN EL FICHERO::::\n"); } if (fclose(punt) != 0) { printf("\n:::::FICHERO GUARDADO:::::\n"); } } } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 54 4/4 Función feof() • Indica si se ha alcanzado el final del fichero apuntado por fp • Prototipo: int feof (FILE *fp); – • fp : es un puntero a un fichero retornado por una llamada a fopen() Valor devuelto: – – Un valor distinto de 0: cuando se intenta leer un registro del fichero y nos encontramos con un EOF (fin del fichero) 0: en cualquier otro caso • Permite leer un fichero cuando el número de registros no se conoce de antemano, leyendo registros hasta que se encuentra el fin del fichero • feof() se puede usar tanto en ficheros binarios como de texto Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 55 55 feof(): Ejemplo de fichero binario // Programa para ilustrar el uso de la función feof() con un fichero binario #include <stdio.h> typedef struct{ char nombre[15]; int existencias; double precio_unitario; }T_ITEM; int main(void) { FILE *fp; T_ITEM item; fp = fopen("items.dat", "rb"); if(fp==NULL) { printf("\nERROR. No se puede abrir el fichero para lectura\n"); } else { fread(&item, sizeof(T_ITEM), 1, fp); while(!feof(fp)) { printf("\nNombre=%-15s Existencias=%d Precio=%7.2f", item.nombre, item.existencias, item.precio_unitario); fread(&item, sizeof(T_ITEM), 1, fp); } fclose(fp); } return 0; } Departamento de Sistemas Informáticos Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 56 56 Escuela Técnica Superior de Ingeniería ICAI feof(): Ejemplo de fichero de texto // Programa para ilustrar el uso de la función feof() con un fichero de texto #include <stdio.h> int main(void) { FILE *fp; char nombre[15]; int existencias; double precio_unitario; fp = fopen("items.txt", "r"); if(fp==NULL) { printf("\nERROR. No se puede abrir fichero para lectura\n"); } else { fscanf(fp,"%s %d %lf", nombre, &existencias, &precio_unitario); while(!feof(fp)) { printf("\nArticulo=%-15s Existencias=%3d Precio=%8.2f", nombre, existencias, precio_unitario); fscanf(fp,"%s %d %lf", nombre, &existencias, &precio_unitario); } fclose(fp); } return 0; } Departamento de Sistemas Informáticos Escuela Técnica Superior de Ingeniería ICAI Tema 1: Introducción. Arquitectura básica y Sistemas Operativos 57 57 Escuela Técnica Superior de Ingeniería ICAI Alberto Aguilera 25 28015 Madrid Tel +34 91 542 28 00 Fax + 34 91 542 31 76 Iwww.icai.upcomillas.es www.upcomillas.es