Unidad V Entradas y Salidas por archivo Concepto de Flujo o Stream en C • Corriente de datos que fluye entre un origen y un destino. ORIGEN Canal o conexión por donde circulan los datos DESTINO • Apertura de Archivo -> Es la conexión entre el PROGRAMA con el dipositivo que contiene el archivo. • Flujos definidos automáticamente por el lenguaje C: – stdin: teclado -> programa – stdout: monitor -> programa – Stderr: mensaje error (pantalla) -> programa • Para acceder a un archivo se hace por medio de un buffer intermedio. – Buffer: Arreglo donde se almacenan los datos dirigidos al archivo o desde el archivo Archivo • Desde el punto de vista de: – S.O. -> Unidad lógica mínima de información. – Usuario -> Serie consecutiva de bytes que contienen información relacionada. • Propiedades: – Nombre: Identifica al archivo dentro de un sistema. – Estructura: Organización interna de la información dentro del archivo. – Tipo: Hace referencia a la información y estructura del archivo. Ejemplo Unix: • Regulares: Tienen info del usuario. • Directorios: Tienen info referente a la localización de otros archivos. • Especiales: Intercambio de información con los dispositivos de E/S. • FIFO: Estructura especial para la comunicación de los procesos. – Atributos: Protección, propietario, tamaño, tiempos. – Operaciones: Creación, eliminación, apertura y cierre, lectura, escritura y modificación. Archivos Este concepto nos permite comprender como accedemos desde C mediante una variable que apunta al tipo FILE a los archivos para la realización de las operaciones deseadas. Archivos Secuenciales o Texto •Se denominan secuenciales debido a que para leer un dato dentro del archivo debemos recorrerlo completo. •Es una secuencia de caracteres organizados en líneas terminadas por un carácter de fin de línea. •Se caracterizan por ser planos, es decir todos los caracteres que lo componen tienen el mismo formato •Es común el uso de la extensión txt, para este tipo de archivos. Acceso aleatorio o Binarios •Son secuencias de ceros y unos. •Permiten el almacenamiento y acceso a la información en forma de bloques o registros. •Su lectura debe hacerse en modo binario y solo se pueden visualizar desde el entorno de un programa en C. •Es común el uso de la extensión dat para este tipo de archivos. Archivos Archivos • Puntero FILE – Los archivos se ubican en dispositivos externos como cintas, discos, CDs, disquetes. – Dentro de un programa se identifican por medio de una variable que es un puntero a una estructura predefinida. – Esta estructura contiene información sobre el archivo: dirección del buffer que utiliza, el modo de apertura del archivo, el último carácter leído del buffer, y otros detalles. • Denominada estructura FILE y se encuentra definida en el archivo cabecera stdio.h. – La sintaxis empleada para declarar un puntero a FILE es la siguiente : FILE * p; Archivos • Apertura de Archivos: – Esta operación supone vincular al archivo con el programa e indicar como va a ser tratado el archivo: binario, de caracteres, etc. – La función empleada devuelve un puntero a la estructura FILE, por lo que en la llamada a la función de apertura debe asignarse a una variable de ese tipo. – Dicha función es fopen() y su prototipo es el que se muestra a continuación: FILE * fopen(const char nombre, const char modo); Archivos • Instrucción para apertura: FILE *archivo; archivo = fopen (nombre_archivo, modo); Función que devuelve un puntero a un archivo que se asigna a una variable del tipo fichero. Si existe algún error devuelve NULL • Cadena de caracteres que indica el tipo de archivo(texto o binario) y el uso (lectura, escritura,etc) Cadena de caracteres que contiene el nombre (y ruta de acceso) del archivo. modos r Abre un archivo para lectura. Si no existe devuelve error. w Abre un archivo para escritura. Si no existe se crea, y si existe se destruye y crea uno nuevo a Abre un archivo para añadir datos al final. Si no existe se crea. + Símbolo utilizado para abrir el archivo para lectura y escritura Archivos • • • En estos modos no se ha establecido el tipo de archivo: texto o binario. La opción por defecto es que el archivo es de modo texto. Debido a esto los modos de abrir un archivo son: rt, wt, at, r+t, w+t, a+t, rb, wb, ab, r+b, w+b, a+b. Esta referencia al tipo de archivo es común en la bibliografía, pero lo que realmente determina el tipo de archivo con el que estamos trabajando son las funciones empleadas para el almacenamiento y lectura de los datos del mismo. Por ejemplo: FILE *archivo; // declaro un puntero tipo FILE archivo= fopen("agenda.txt", "a"); La función fopen() devuelve un puntero a archivo, si el mismo tiene el valor NULL significa que no se puede realizar la operación. Por ejemplo: FILE *archivo; archivo=fopen("prueba.txt", "r+"); // abre el archivo de texto prueba.txt en modo a+ if(archivo==NULL) // de este modo se controla si la operación de //apertura fue exitosa con r+ { printf(“No se pudo abrir en r+”); archivo=fopen(“prueba.txt”, “w+”); if(archivo==NULL) { printf(“No se pudo crear el archivo.”); exit(0); } } Archivos • Cierre de Archivos: – Los archivos en C trabajan con una memoria intermedia: el buffer. – Al terminar la ejecución del programa, puede que haya datos en el buffer, y si estos no se vuelcan al archivo, éste quedará sin las últimas modificaciones. – Por esto, siempre que se termina de procesar un archivo y siempre que se termine la ejecución de un programa se deben cerrar todos los archivos abiertos, para que, entre otras tareas, se vuelquen los datos del buffer. – Para ello se emplea la función fclose() cuyo prototipo es el siguiente: int fclose(FILE *F); – En donde F es el puntero al archivo devuelto por la función fopen() en el momento de apertura del mismo. Archivos • Inicio y fin de un archivo: – Todos los archivos tienen un puntero que indica la posición dentro del archivo en la que nos encontramos. – En la apertura del archivo, dicho puntero se encuentra al inicio (excepto cuando es abierto en el modo a), y con cada lectura de datos avanza automáticamente a la posición siguiente. – La función feof() nos permite saber si hemos llegado al final del archivo. – Esta función devuelve un valor distinto de cero cuando se lee el carácter de fin de archivo, en caso contrario devuelve 0. El prototipo de esta función se encuentra en el archivo stdio.h y es: int feof(FILE * F); – Si hemos llegado al final del archivo y necesitamos seguir trabajando con él, podemos emplear la función rewind() para situar al puntero al inicio del archivo. El prototipo de rewind() es: void rewind(FILE * F); Archivos • Posición y tamaño del archivo (1) – Función ftell() • Esta función permite obtener la posición actual del puntero de lectura/escritura dentro del archivo. • El valor devuelto por la función será la correspondiente posición medidas en cantidad de bytes desde el inicio del archivo, o bien, el valor -1 si hay algún error. • Para la llamada a esta función se requiere pasar como argumento el puntero a una estructura FILE. El prototipo es el siguiente: long int ftell (FILE *F); Archivos • Posición y tamaño del archivo (2) – Función fseek() • Esta función permite situar el cursor del fichero en la posición deseada. El prototipo de la función fseek() es el siguiente: int fseek(FILE *F, long int desplazamiento, int referencia); • El valor que devuelve fseek() es cero si la función tuvo éxito, y un valor distinto de cero si hubo algún error. Los argumentos que requiere esta función son: – Un puntero a una estructura FILE (del archivo sobre el que deseamos reubicar el cursor). – El valor del desplazamiento, que indica el número de bytes a mover. – Una referencia, que indica el origen del desplazamiento. Este parámetro puede tomar tres valores: » SEEK_SET o 0: el desplazamiento se cuenta desde el principio del fichero. » SEEK_CUR o 1: el desplazamiento se cuenta desde la posición actual del cursor. » SEEK_END o 2: el desplazamiento se cuenta desde el final del fichero. Archivos • Archivos secuenciales o de texto: – Las funciones de entrada / salida que empleamos con archivos tienen similitud con las empleadas para los flujos stdin (teclado) y stdout (monitor). • fputc() y fgetc() – La función fputc() se emplea para escribir un carácter en un archivo. El valor devuelto por esta función es el carácter escrito o EOF si no pudo escribirlo. La sintaxis de la llamada a esta función es: fputc(c, puntero_archivo); En donde c es el caracter a escribir y puntero_archivo es un puntero al tipo FILE. – La función fgetc() lee un caracter del archivo asociado al puntero FILE. Devuelve el caracter leído o EOF. El prototipo de esta función es: int fgetc(FILE *F); Archivos Por ejemplo: #include <stdio.h> int main (int argc, char *argv[ ]) { FILE * F; char c='A'; F=fopen("archivo.txt", "a+"); if (F==NULL) { printf("Error al abrir"); exit(0); } for(; c<'Z';) fputc(c++,F); rewind(F); for(c='Z'; c>'A';c--) printf("%3c",fgetc(F)); fclose(F); return 0; } Archivos • fputs() y fgets() – Estas funciones escriben y leen una cadena de caracteres del archivo asociado. – La función fputs() escribe una cadena de caracteres, devuelve EOF si no ha podido escribir la cadena y un valor no negativo si la escritura es correcta. – La función fgets() lee una cadena de caracteres del archivo, la lectura finaliza cuando encuentra el carácter de fin de línea o cuando ha leído n-1 caracteres, en donde n es un argumento entero de la función. – Los prototipos de estas funciones son: int fputs(char * cadena, FILE * F); char * fgets(char * cadena, int tamaño, FILE * F); Archivos Por ejemplo: #include <stdio.h> #include <stdlib.h> #include <string.h> int main( int argc, char *argv[]) { FILE *entrada, *salida; char cad[40]; entrada=fopen("archivo.txt", "r"); salida=fopen("archivo2.txt", "a"); if (entrada==NULL || salida == NULL) { printf("Error al abrir"); exit(0); } while(fgets(cad,40,entrada)) //realiza el ciclo hasta devolver puntero NULL { if(strlen(cad)>=10) fputs(cad,salida); else { puts(cad); printf("\n\n"); } } fclose(entrada); fclose(salida); return 0; } Archivos • fprintf() y fscanf() – Estas funciones permiten escribir o leer variables de cualquier tipo de dato estándar. – Los prototipos de estas funciones se encuentran en stdio.h y son: int fprintf(FILE * F, “cadena de control”, [lista de parámetros]); int fscanf(FILE * F, “cadena de control”, [lista de parámetros]); Archivos Por ejemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h> #include <string.h> #include <ctype.h> #include "texto.h" int main (int argc, char *argv[]) { int b; if (argc<2) printf("Debe ingresar por comandos el nombre del archivo"); else { b=apertura(argv[1]); if (b) { cargart(argv[1]); mostrart (argv[1]); } printf("\n\t\t Fin del programa.........................\n\n"); } return 0; } Archivos Biblioteca archivo.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 void cargat (char nom_archivo []) { datos a; FILE *parch; parch=fopen(nom_archivo, "a+"); a= leer(); fprintf(parch,"%12s %10s %8i %10f %8i %10s %8i\n",a.apell, a.nomb, a.edad, a.salario, a.f_nacim.dia, a.f_nacim.mes, a.f_nacim.anio); fclose(parch); return; } void mostrart (char nomb_archivo []) { datos a; char aux[100]; FILE *parch; parch=fopen(nomb_archivo, "r"); rewind (parch); encabezado(); while (!feof(parch)) { fscanf(parch,"%12s %10s %8i %10f %8i %10s %8i\n",a.apell,a.nomb, &a.edad, &a.salario, &a.f_nacim.dia, a.f_nacim.mes, &a.f_nacim.anio); printf("%12s %10s %8i %10f %8i %10s %8i\n",a.apell, a.nomb, a.edad, a.salario, a.f_nacim.dia, a.f_nacim.mes, a.f_nacim.anio); } fclose(parch); return ; } Archivos • Archivos de acceso aleatorio o binarios – fwrite() y fread() • La función fwrite() se emplea para escribir en un archivo. El prototipo de esta función es: int fwrite(void *direccion, int tam, int cantidad, FILE * F); Donde: • *dirección: es un puntero a la dirección de memoria donde se encuentra el dato que quiero almacenar en el archivo. • tam: es el tamaño en bytes de cada registro a almacenar. • cantidad: es la cantidad de registros que se van a almacenar. • F: es el puntero por medio del cual se referencia el archivo en el cual se almacenarán los datos. Esta función permite escribir en un archivo uno o varios registros de la misma longitud almacenados a partir de una dirección de memoria determinada. El valor devuelto por la función es el número de registros escritos. Archivos • Archivos de acceso aleatorio o binarios – La función fread() lee un número de elementos de la cantidad de bytes especificada y los almacena en memoria a partir de la posición indicada. int fread(void *direccion, int tam, int cantidad, FILE * F); Donde: • *dirección: es un puntero a la dirección de memoria donde se almacenarán los registros leidos. • tam: es el tamaño en bytes de cada registro a leer. • cantidad: es la cantidad de registros que se van a leer. • F: es el puntero por medio del cual se referencia el archivo desde el cual se leerán los datos. Esta función permite leer desde un archivo uno o varios registros de la misma longitud El valor devuelto por la función es el número de registros leídos. Archivos Por ejemplo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <stdio.h> #include <string.h> #include <ctype.h> #include "texto.h" int main (int argc, char *argv[]) { int b; if (argc<2) printf("Debe ingresar por comandos el nombre del archivo"); else { b=apertura(argv[1]); if (b) { cargarb(argv[1]); mostrarb(argv[1]); } printf("\n\t\t Fin del programa.........................\n\n"); } return 0; } Archivos • Biblioteca archivo.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void cargarb (char nom_archivo []) { datos a; FILE *parch; parch=fopen(nom_archivo, "a+"); a= leer(); fwrite(&a,sizeof(a),1,parch); fclose(parch); return; } void mostrarb (char nomb_archivo []) { datos a; int cant,i; char aux[100]; FILE *parch; parch=fopen(nomb_archivo, "r"); fseek(parch,0,SEEK_END); cant=ftell(parch)/sizeof(a); fseek(parch,0,SEEK_SET); encabezado(); for (i=0;i<cant;i++) { fread(&a,sizeof(a),1,parch); printf("%12s %10s %8i %10f %8i %10s %8i\n",a.apell, a.nomb, a.edad, a.salario, a.f_nacim.dia, a.f_nacim.mes, a.f_nacim.anio); } fclose(parch); return ; }