Departamento de Informática Universidad Técnica Federico Santa María Archivos Programación de Computadores Prof. Teddy Alfaro ¿qué es un archivo? • Un archivo es una estructura de datos de un mismo tipo, sean éstos simples o estructurados. Un archivo se almacena en un dispositivo secundario (diskette, disco duro, cinta, etc), de manera que los datos contenidos en un archivo antes, durante y después de un procesamiento (ejecución de un programa) no se pierden. 1 Usos de Archivos • La entrada y salida estándar de datos (teclado y pantalla) pueden ser reemplazado por el uso de archivos. • Los programas utilizan archivos para comunicarse con el mundo exterior y con otros programas. Información Masiva • Imaginemos que hacemos un programa que requiere que se le ingresen una gran cantidad de datos. Pensemos, si estamos haciendo las pruebas al programa, por cada corrida debemos ingresar de nuevo los datos. • Por otra parte, pensemos, nos interesa que nos muestre una gran cantidad de datos, ordenados y con estadísticas. El mostrarlos por pantalla se limita a mostrar sólo lo ultimo que queda en pantalla 2 Leer información, guardar información Archivo almacenado en algún dispositivo de memoria secundaria Flujo de información, pueder binario o de texto Carga de datos en memoria principal para que puedan ser usados por programas Proceso de escritura archivo archivo flujo Proceso de Lectura flujo Memoria principal Memoria principal Flujos Flujos de Texto: • Es una secuencia de caracteres. • En un flujo de texto, pueden ocurrir ciertas conversiones de caracteres si el entorno del sistema lo requiere. • El número de bytes escritos y leídos puede no ser iguales.} Flujos Binarios: • Es una secuencia de bytes con una correspondencia de uno a uno con los dispositivos externos. • No se realizan conversiones de caracteres. • El número de bytes escritos y leídos es el mismo. 3 Archivos para C • La entrada y salida a archivos es un aspecto dependiente del S.O. Las librerías de C proveen un conjunto de funciones para trabajar con archivos • Se pueden distinguir 2 tipos de funciones de E/S, las tipos Unix que trabajan sin buffer, y la estandar ANSI que utilizan buffer intermedio (trabajaremos con el sistema ANSI). Sistema de Archivos ANSI C • La librería stdio.h nos provee un cojunto de funciones: – – – – – – – – – – – fopen( ): abrir un archivo fclose( ): cerrar un archivo fputc ( ): escribe un char en archivo fgetc ( ): lee un char de un archivo fseek ( ): busquede de byte fprintf ( ): printf para archivos fscanf ( ): scanf para archivos feof ( ): indentificador de final de archivo ferror ( ): devuelve 1 o 0 si hubo error en el flujo rewind ( ): se posiciona al inicio del archivo remove ( ): borra una archivo 4 Stream, FILE • Las operaciones de un archivos se hacen a través de un stream. Un stream es una serie ordenada de byte (muchos bytes). • Leer o escribir un archivo implica leer o escribir un stream. • Para asociar un stream con un archivo se crea un puntero a una estructura FILE, la cual contiene la información necesaria para interactuar con el S.O. Sistema de archivos • La lógica para trabajar con archivo será: – Para lectura: abrir un archivo, leo la información y luego se cierra el archivo – Para escritura: abrir (crear) archivo, escribir la información y luego cerrar el archivo. • La inicializacion de un *FILE, o dicho en otras palabras, la apertura de un flujo de archivo se hace con la función fopen(archivo, modo). El cierre del flujo se hace con fclose(archivo) 5 Apertura de archivo • El prototipo de fopen es: FILE *fopen(const char *nombre_archivo, const char *modo); • Donde – Nombre_archivo: es el archivo con el cual se trabajará (path incluido). – Modo: es el modo de acceso para el stream Modos de Acceso • El modo indica si el archivo se abrirá, o si se creará, si es de texto o binario. Los modo posibles para C son: – r: sólo lectura. El archivo debe existir. – w: se abre para escritura, se crea un archivo nuevo o se sobreescribe si ya existe. – a: añadir, se abre para escritura, el cursor se sitúa al final del archivo. Si el archivo no existe, se crea. – r+: lectura y escritura. El archivo debe existir. – w+: lectura y escritura, se crea un archivo nuevo o se sobreescribe si ya existe. – a+: añadir, lectura y escritura, el cursor se sitúa al final del archivo. Si el archivo no existe, se crea. – t: tipo texto, si no se especifica "t" ni "b", se asume por defecto que es "t" – b: tipo binario. 6 Ejemplo FILE *a, *b, *c, *d; main( ) { a=fopen(“datos.txt”, “r”); b=fopen(“nombres.dat”, “a+”); c=fopen(“ipc.tex”, “rt”); d=fopen(“c:/cambios.rtf”, “r+b”); .......... } Error al abrir un archivo • Abrir una archivo (lectura, agregar) que no existe causa un error. Esta situación puede ser facilmente detectada de la siguiente forma: FILE *arch; If ((arch=fopen(nombre_archivo,modo))==NULL) { printf(“no es posible leer %s”,nombre_archivo); exit(1); } Sin no existe el archivo, la función fopen devuelve NULL 7 Cerrar un Archivo • No se debe olvidar cerrar todos los archivos abiertos. Al cerrar los archivos, se guardan los datos que aún están en el buffer y además actualiza algunos datos de la cabecera del arch que mantiene el S.O. Además, libera el archivo para que otros programas puedan abrirlo. Cerrando Archivos • La función es fclose, y su prototipo es int fclose(FILE *archivo); • Devuelve cero si no hay error, y EOF en caso contrario. • Ejemplo FILE *arch; arch=fopen(“deuda.grande”,”r”); ...... fclose(arch); 8 Trabanjando sobre archivos • Las operaciones de lectura o escritura que podemos realizar sobre los archivos son funciones de la librería stdio.h que pueden trabajar en base a: – Caracteres (char) – Lineas – bloques Función fgetc • Lectura de sólo un carácter desde un archivo, el prototipo de esta función es: int fgetc(FILE *archivo); • El valor de retorno es un carácter leído como un unsigned char convertido a int. • Si al leer no hay un carácter disponible el valor de retorno es EOF 9 Función fputc • Escritura de sólo un carácter hacia un archivo int fputc(int carácter, FILE *archivo); • El valor de retorno es el carácter escrito, si la operación de escritura fue realizada, de los contrario devuelve EOF. • Los parámetros son el carácter convertido a int y un puntero FILE al archivo Función feof • Prototipo int feof(FILE *archivo); • Función que se utiliza pqra comprobar si se ha llegado a fin de archivo (end of file) • En los archivos guardas datos de un mismo tipo ya sean simple o estructuras, no tenemos información de cuantos registros hay, la idea será ir realizando lecturas consecutivas hasta que se llegue a final de archivo • El valor de retorno es 1 cuando se ha llegado a fin de archivo, de los contrario el retorno es 0. 10 Función rewind • Prototipo: void rewind(FILE *archivo); • Función rebobinar, sitúa el cursor de lectura/escritura en el primer elemento del archivo (la información que fue registrada primero que todas) Ejemplo 1 • Realizar un programa en el cual guarde en un archivo la información introducida por el usuario a través del teclado. Se termina la introducción por el teclado con el carácter $. • Realizar un programa que lea lo introducido. 11 Ejemplo 1 #include <stdio.h> int main(){ FILE *Archivo; char c; if ((Archivo=fopen("datos.dat","w+"))==NULL){ printf("No se puede abrir el archivo"); return 1; } do{ c=getchar(); putc(c,Archivo); }while(c!='$'); rewind(Archivo); while(!feof(Archivo) ){ c=fgetc(Archivo); printf("%c",c); } fclose(Archivo); return 0; } Ejemplo 2 // Muestra dos veces el archivo. #include <stdio.h> int main() { FILE *arch; arch = fopen("ejemplo1.c", "r"); while(!feof(arch)) fputc(fgetc(arch), stdout); rewind(arch); while(!feof(arch)) fputc(fgetc(arch), stdout); fclose(arch); getchar(); return 0; } 12 fprintf( ) • Prototipo int fprintf(FILE *archivo, const char *formato,...) • Impresión en archivo, funciona de manera similar que printf, pero no imprime la información por pantalla (stdout) sino que la salida es dirigida a un archivo • El retorno es el numero de caracteres enviados, si es negativo se produce un error en la salida fscanf( ) • Prototipo: int fscanf(FILE *archivo, const char *formato,...) • Ingreso de valores, funciona de manera similar a scanf, con la diferencia que los datos no son de teclado (stdin), sin que la entrada se toma desde un archivo • Retorna el número de datos asignado y EOF si ocurrió un error 13 ejemplo Programa Ingreso datos Programa mustra información #include <stdio.h> FILE *arch; #include <stdio.h> FILE *inf; int main(int argc, char *argv[]){ int i,n1,n2,n3; arch=fopen("notas.dat","w"); for (i=0;i<5;i++){ printf("\nnotas alumno %d ",i); printf("ingrese sus 3 notas"); scanf("%d %d %d",&n1,&n2,&n3); fprintf(arch,"%d %d %d ",n1,n2,n3); } fclose(arch); return 0; } int main(int argc, char *argv[]){ int i,n1,n2,n3; inf=fopen("notas.dat","r"); i=0; while(!feof(inf) ){ fscanf(inf, "%d %d %d", &n1, &n2, &n3); printf("%d %d %d ",n1, n2, n3); printf("alumno %d prom=%f\n",i,(n1+n2+n3)/3.0); i++; } fclose(inf); return 0; } Función fflush • Prototipo int fflush(FILE *archivo); • Esta función fuerza la salida de los datos acumulados en el buffer de salida del archivo. Para mejorar el manejo de archivos se utilizan buffers (almacenes temporales de datos en memoria) las operaciones de salida se hacen a través del buffer, y sólo cuando el buffer se llena se realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese buffer de un modo manual. • El valor de retorno es 0 en caso de éxito,y EOF en caso contrario 14 Función fseek( ) • Prototipo int fseek(FILE *archivo, long int desp, int origen); • Función cuya utilidad es posicionar el cursor del archivo para leer o escribir en un lugar deseado • Retorna 0 en caso de éxito • Parámetros: el archivo, el desplazamiento desp en bytes • El parametro de origen – SEEK_SET: – SEEK_CUR: – SEEK_END: comienzo de archivo ubicación actual fin de archivo ftell( ) • Prototipo: long int ftell(FILE *archivo); • Función para averiguar cuál es la posición actual del cursor de lectura/escritura de un archivo • El retorno será la pasición o –1 si se produjo un error 15 fgets() • Prototipo char *fgets(char *cadena,int n ,FILE *archivo); • • • • Función para lectura de string (cadena de caracteres). Lee: n-1 caracteres o hasta que encuentra salto de línea Cuando encuentra salto de línea, este también es leído Los parámetros son: la cadena a leer, número máximo de caracteres a leer y el FILE. • El valor de retorno es un puntero a la cadena leída en caso de lectura correcta, de lo contrario retorna NULL (ejemplo: hacer una lectura y es fin de archivo fputs() • Prototipo: int fputs(const char *cadena,FILE *archivo); • Función que escribe una cadena en un archivo. La cadena es escrita sin el valor de retorno y sin el carácter de finalización de string • Parámetros: cadena a escribir, archivo • El valor de retorno es un número positivo o EOF en caso de error 16 Ejemplo #include <stdio.h> int main() { char nombre[10]="datos.dat", linea[81]; FILE *arch; arch = fopen( nombre, "r" ); printf( "archivo: %s -> ", nombre ); if ( arch ) printf( "existe (ABIERTO)\n" ); else { printf( "Error (NO ABIERTO)\n" ); return 1; } printf( "La primera linea del archivo: %s\n\n", nombre ); printf( "%s\n", fgets(linea, 81, arch) ); if( !fclose(arch) ) printf( "\narchivo cerrado\n" ); else { printf( "\nError: archivo NO CERRADO\n" ); return 1; } return 0; } Ejemplo #include <stdio.h> int main( ) { char nombre[11]="datos2.dat"; FILE *arch; arch = fopen( nombre, "w" ); printf( "archivo: %s -> ", nombre ); if( arch ) printf( "creado (ABIERTO)\n" ); else { printf( "Error (NO ABIERTO)\n" ); return 1; } fputs( "Esto es un ejemplo usando \'fputs\'\n", arch ); if( !fclose(arch) ) printf( "\narchivo cerrado\n" ); else { printf( "\nError: arch NO CERRADO\n" ); return 1; } return 0; } 17 Guardando registros • Al trabajar con estructuras o arreglos de estructuras, los más natural es guardar la información en un archivo, para que una vez terminado el programa la información no se pierda, y pueda ser recuperada nuevamente en cualquier momento. • A continuación veremos algunas funciones para trabajar con estructuras y archivos fread( ) • Prototipo size_t fread(void *ptr,size_t tamaño, size_t nregistros, FILE *archivo); • Función capaz de leer desde un archivo uno o varios registros de la misma longitud a partir de una dirección de memoria determinda • El valor de retorno es el número de registros leídos • Parámetros: una puntero a la memoria donde se almacenarán, el tamaño de cada registro, el número de registros a leer y el archivo de donde se lee 18 fwrite() • Prototipo: size_t fwrite(void *ptr, size_t tamaño, size_T nregistros,FILE *archivo); • Función que permite escribir en un archivo uno o varios registros de una misma longitud almacenados a partir de una dirección de memoria determinada • El valor de retorno es el número de registros escritos • Parámetros: una puntero a la memoria donde se almacenarán los datos, el tamaño de cada registro, el número de registros a escribir y el archivo de donde se escribiran #include <stdio.h> struct computador { char placa[20], procesador[20]; int memoria,velocidad,t_disco; } stock[4]={ {"asus","intel p4",256, 2600,2} , {"msi","amd athlon", 512, 2800,80} , {"microstar", "celeron", 2400, 60} , {"A-open", "Septron", 3000, 120} }, s; FILE * arch; int main(int argc, char *argv[]){ arch=fopen("computer.tex", "w+"); fwrite(&stock, sizeof(stock[0]),3,arch); fwrite(&stock[3], sizeof(stock[3]), 1, arch); rewind(arch); printf("placa \t procesador \t memoria \t velocidad \t disco duro \n"); while(!feof(arch) ){ fread(&s, sizeof(s), 1, arch); printf("%s\t\t%s\t\t%d\t\t%d\t\t%d\n", s.placa, s.procesador,s.memoria,s.velocidad,s.t_disco); } fclose(arch); return 0; } 19 #include <stdio.h> struct computador { char placa[20], procesador[20]; int memoria,velocidad,t_disco; } s; FILE * arch; int main(int argc, char *argv[]){ arch=fopen("computer.tex", “r"); while( fread(&s,sizeof(s),1,arch) && !feof(arch) ) { printf("%s\t\t%s\t\t%d\t\t%d\t\t%d\n", s.placa, s.procesador,s.memoria,s.velocidad,s.t_disco); } fclose(arch); return 0; } Creando un nuevo tipo: typedef typedef float decimal; typedef int* puntero; typedef struct { char nombre[20]; int edad; float estatura,peso; } persona; int main( ) { decimal f; puntero k; persona p; f=2.9; k=(puntero)malloc(sizeof(int),1); strcpy(p.nombre,”pedro”); p.edad=44; p.estatura=1.80; p.peso=(decimal)85; return 0; } struct persona { char nombre[20]; int edad; float estatura,peso; }; int main( ) { float f; int *k; struct persona p; f=2.9; k=(int *)malloc(sizeof(int),1); strcpy(p.nombre,”pedro”); p.edad=44; p.estatura=1.80; p.peso=(float)85; return 0; } 20