Guía # 11: Archivos de texto UNIVERSIDAD DON BOSCO FACULTAD DE ESTUDIOS TECNOLÓGICOS COORDINACION DE COMPUTACION GUIA DE LABORATORIO #11 CICLO: 01/2016 Nombre de la Practica: Archivos de texto Lugar de Ejecución: Centro de Computo Tiempo Estimado: 2 horas y 30 minutos MATERIA: Programación de Algoritmos I. OBJETIVOS Que el estudiante: • Elabore aplicaciones en C++ que utilicen archivos de texto para almacenar información masiva a largo plazo. • Implemente la codificación para transferir datos de arreglos complejos (tipo struct) hacia archivos y viceversa II. INTRODUCCION TEORICA Uso de archivos en C++ Un archivo o fichero es un conjunto sistematizado de información homogénea. Consta de una colección de información, estructurada en unidades de acceso llamada artículos o registros. Existen varias clasificaciones o tipos de archivos, en este caso los dividiremos en dos: • Archivos de texto: Son aquellos que pueden contener cualquier clase de datos y de tal manera que son “entendibles” por la gente. Los datos en un archivo de texto se almacenan usando el código ASCII, en el cual cada carácter es representado por un simple byte. Debido a que los archivos de texto utilizan el código ASCII, se pueden desplegar o imprimir. En este tipo de archivos, todos sus datos se almacenan como cadenas de caracteres, es decir, los números se almacenan con su representación ASCII y no su representación numérica, por lo tanto no se pueden realizar operaciones matemáticas directamente con ellos. Además este tipo de archivos tienen un carácter que define el final del archivo, conocido como EOF. • Archivos binarios: Este tipo de archivos almacenan los datos numéricos con su representación binaria. Pueden ser archivos que se utilicen para almacenar imágenes o bases de datos. Estos no tiene un carácter de fin de archivo. Existe una manera de manipular ficheros en C++ mediante los denominados streams. Un stream representa un flujo de información: desde el programa a un dispositivo o periférico de salida, o desde un periférico de entrada al programa Programacion de Algoritmos 1 Guía # 11: Archivos de texto La forma de utilizar un stream de entrada es: stream_entrada >> variable; La forma de utilizar un stream de salida es: stream_salida << información; Hasta el momento se han utilizado dos streams predefinidos: • cin es un stream de entrada asociado al teclado • cout es un stream de salida asociado a la pantalla Pueden definirse stream de entrada y/o salida y asociarlos a un fichero, de manera que se puedan recibir datos del fichero y/o enviar datos al fichero respectivamente, la librería que se debe utilizar es <fstream> Dentro de esta librería existen tres clases para manejar ficheros: ifstream, ofstream y fstream. La primera está orientada a ficheros de entrada, la segunda a ficheros de salida, y la tercera puede manejar cualquiera de los dos tipos o ficheros de entrada y salida. Para crear un manejador de archivo se debe declarar un stream mediante el constructor: ifstrem/ofstrem/fstream nombre_stream (nombre_fichero, opciones); Los parámetros son opcionales. Si están presentes sirven para realizar la apertura del fichero. El nombre del fichero es un string que indica la ruta del fichero que se asocia al stream. Las opciones indican diferentes modos entre los cuales se encuentran: ios:: in Crea un stream de entrada, es decir, para lectura de datos del fichero ios::out Crea un stream de salida, es decir, para escritura de datos en el fichero ios::ate Hace que la posición inicial sea al final del fichero ios::app Se sitúa al final del fichero antes de cada escritura ios::trunc ios::nocreate noreplace binary Borra cualquier cosa que pudiera haber en el fichero Si el fichero no existe fallará Si el fichero existe fallará Abre el fichero como binario Operadores << Escribe en el archivo >> Lee desde el archivo Programacion de Algoritmos 2 Guía # 11: Archivos de texto Algunos métodos de la clase stream open(nombre_fichero, Con los mismos parámetros que el constructor. Puede usarse cuando en el constructor se ignoró la apertura del fichero. close() Cuando se desea cerrar un stream eof() Es una función que devuelve un valor diferente a 0 (true) si se llegó al fin de fichero de otro modo devuelve 0 (false) is_open() Es una función que devuelve un valor diferente a 0 (true) si el fichero asociado al stream está abierto de otro modo devuelve 0 (false). tellp() Es una función que devuelve como resultado la posición actual (tipo pos_type) de un stream de salida seekp(posición, posición_inicial) Sitúa el lugar de escritura indicada en posición en forma relativa a posicion_inicial, la cual puede ser ios::beg (comienzo), ios::cur (actual), ios::end (fin). seekg(posición, posición_inicial) Sitúa el lugar de lectura indicada en posición en forma relativa a posicion_inicial, la cual puede ser ios::beg (comienzo), ios::cur (actual), ios::end (fin). write(datos,cantidad) Escribe el número de caracteres indicado en el segundo parámetro desde el buffer suministrado por el primero. read(buffer,cantidad) Lee el número de caracteres indicado en el segundo parámetro dentro del buffer suministrado por el primero. put(carácter) Sirve para cualquier stream de salida, e inserta un carácter en el stream. get(variable) Sirve para cualquier stream de entrada, y lee un carácter desde el stream. getline(buffer, cantidad) Sirve para cualquier stream de entrada, y lee una línea completa desde el stream. Programacion de Algoritmos 3 Guía # 11: Archivos de texto Ejemplos de operaciones sobre archivos Escribir en un archivo de texto // escribiendo en un archivo de texto #include <iostream> #include <fstream> using namespace std; main() { ofstream ejemplo("ejemplo.txt"); // Crea un archivo de salida if(ejemplo.is_open()){ //Comprueba si el archivo esta abierto // Enviamos dos cadenas al archivo de salida: ejemplo<<"Esto es una linea.\n"; ejemplo<<"Esto es otra linea.\n"; ejemplo.close(); // Cierra el acceso al archivo ejemplo.clear(); //limpia buffer lectura del flujo del archivo } } Leer contenido de un archivo de texto // leer un archivo de texto #include <iostream> #include <fstream> using namespace std; int main(){ char buffer[256]; ifstream ejemplo("ejemplo.txt"); if(!ejemplo.is_open()){ cout<<"Error al abrir el archivo"; exit(1); } while(!ejemplo.eof()){ ejemplo.getline(buffer,100); cout<<buffer<<endl; } system("pause"); return 0; } Programacion de Algoritmos 4 Guía # 11: Archivos de texto III. MATERIALES Y EQUIPO Para la realización de la guía de práctica se requerirá lo siguiente: No. Requerimiento Cantidad 1 Guía de Laboratorio #11 de Programación de Algoritmos 1 2 Memoria USB 1 3 Computadora con compilador de C++ 1 IV. PROCEDIMIENTO 1. Cree una carpeta de trabajo llamada /PALguia11_CARNET/ para que guarde ahí a sus archivos de ejemplos y del análisis de resultados. 2. Desarrolle a continuación los siguientes ejemplos, teniendo el cuidado de leer las aclaraciones previas y conclusiones acerca de los mismos Parte 1: Almacenando información en un archivo de Texto 3. El siguiente programa almacena información de la cuenta de ahorros de n clientes. Primero crea un archivo de texto (cliente.txt) y luego solicita uno a uno los datos de c/cuenta, para ir escribiéndolas al final del archivo de texto. Nombre de programa GUIA11_ejemplo1 : Programa que crea un archivo de texto (cliente.txt), para almacenar ahí a la información de una lista de clientes #include <iostream> #include <stdlib.h> #include <fstream> using namespace std; main( ){ //datos generales de una cuenta de ahorros int cuenta; char nombre[15]; double saldo; int n,i;// total de cuentas a registrar y contador de cuentas cout<<"Ingreso de datos de cuentas de ahorros y su almacenamiento en archivo de texto\n"; //ofstream abre el archivo en forma de escritura // ios::app agrega los datos al final del archivo ofstream archivoclientessalida("cliente.txt", ios::app); //Si no se puede crear el archivo, finaliza aplicacion if (!archivoclientessalida){ cout<<"No se puede abrir el archivo" <<endl; system("pause"); exit(1); //finaliza a la aplicacion general } Programacion de Algoritmos 5 Guía # 11: Archivos de texto cout<<endl<<"Digite el numero de clientes a ingresar: "; cin>>n; i=1;//num. cuenta inicial (1) //Recibe #cuenta, nombre y saldo while (i<=n) { cout<<endl; cout<<"\n\nDigite los Datos de cuenta # "<<i<<" :"; cout<<"\nNumero de cuenta ?? "; cin>>cuenta; cout<<"\nNombre de cliente ?? "; fflush(stdin); cin.getline(nombre,15); cout<<endl<<"Saldo ?? $ "; cin>>saldo; //Escribe datos en el archivo de texto //solo un dato por linea archivoclientessalida<<cuenta<<"\n"<<nombre<<"\n"<<saldo<<endl; i++; //prox cuenta a ingresar } //fin de while archivoclientessalida.close(); cout<<"\nSE TERMINO DE AGREGAR DATOS AL ARCHIVO"; cout<<endl; system("pause"); }//fin de main 4. Ejecute el programa anterior e ingrese los datos del cliente. Cuando finalice el programa, verifique en su carpeta que se creó el archivo cliente.txt. Abra este archivo de texto y confirme que los datos brindados fueron escritos correctamente. Parte 2: Recuperando información a un archivo de texto. 5. Cree un nuevo código fuente, para digitar el siguiente cod. fuente, que permite recuperar los datos del archivo cliente.txt (creado en el ejemplo anterior) hacia un arreglo de struct apropiado. Nombre del programa GUIA11_ejemplo2: Programa que recupera datos de un archivo de texto (cliente.txt). #include <iostream> #include <stdlib.h> #include <fstream> #include <iomanip> using namespace std; #include<conio.h> #include<string.h> Programacion de Algoritmos 6 Guía # 11: Archivos de texto struct datoscuenta{ int cuenta; char nombre[15]; float saldo; }; main(){ //guarda info. de N cuentas recuperadas de archivo datoscuenta cuentas[50]; int cc=0; //contador cuentas recuperadas char linea[8]; //lee texto de una linea completa del archivo // ifstream abre el archivo en forma de lectura ifstream archivoclientesentrada("cliente.txt",ios::in); if (!archivoclientesentrada){ cout<<"no se puede abrir el archivo" <<endl; system("pause"); //salir del programa si ifstream no puede abrir el archivo exit(1); } else{ //Recupera del archivo a cada registro //genera ciclo infinito para lectura del archivo while (true){ //Lee datos desde archivo y almacenan en las struct archivoclientesentrada.getline(linea,8); if(strlen(linea)!=0){ cc++; //incrementa contador de cuentas recuperadas cuentas[cc].cuenta=atoi(linea); archivoclientesentrada.getline(cuentas[cc].nombre,15); archivoclientesentrada.getline(linea,8); cuentas[cc].saldo=atof(linea); }else break; //finaliza ciclo while }//fin de while //muestra info. de cuentas recuperadas cout<<"Total cuentas registradas: "<<cc<<"\n\n"; cout<<setw(6)<<"Cuenta"<<setw(13)<<"Nombre"<< setw(8)<<"Saldo"<<endl; for(int i=1;i<=cc;i++){ cout<<setw(6)<<cuentas[i].cuenta<< setw(13)<<cuentas[i].nombre<< setw(8)<<cuentas[i].saldo<<endl; }//fin for i }//fin de if archivoclientesentrada.close(); cout<<endl; Programacion de Algoritmos 7 Guía # 11: Archivos de texto system("pause"); }//fin main 6. Compile y ejecute el programa. Confirme que se leen correctamente los datos del archivo hacia la aplicación. Parte 3 : Almacenando y recuperando información de Archivos binarios 7. Ahora crea un conjunto de archivos (librerías y cod. de aplicacion), que permita administrar la información de N empleados desde la aplicación, para luego ser almacenadas en un archivo de texto (con acceso en modo binario). 8. Descargue los archivos complementarios de esta práctica. De la descarga, seleccione el archivo de librería (GUIA11_Menus.h) y ubíquelo en su carpeta de trabajo. 9. Prepare un nuevo archivo de cabecera denominado GUIA11_adminCuentas.h. Luego digite ahí al siguiente código fuente inicial: Nombre del programa GUIA11_adminCuentas.h #include <iostream> #include <fstream> using namespace std; #include <string.h> //Funciones generales (Prototipos) struct empleado{ //Estructura datos empleados private: //acceso local (solo desde metodos del struct) //campos char nombre[20]; int edad; float salario; public: //acceso externo/global //Metodos (prototipos) empleado(); //constructor }; //fin struct //Definicion de Metodos del struct empleado::empleado(){ //constructor strcpy(nombre,"FALTA"); edad=0; salario=0; }//fin metodo constructor //Funciones generales (Definiciones) Programacion de Algoritmos 8 Guía # 11: Archivos de texto 10. Guarde el archivo anterior. Luego, prepare un nuevo código (.cpp) y digite ahí el siguiente código para el programa principal, el cual usara la librería anterior. Nombre del programa GUIA11_ejemplo3.cpp #include <iostream> using namespace std; #include <stdlib.h> #include <iomanip> #include<conio.h> #include<windows.h> #include "GUIA11_adminCuentas.h" #include "GUIA11_Menus.h" main(){ int totEmp=0; //Total de empleados registrados empleado Emple[100]; //arreglo de struct bool salir=false; //prepara menu menu mimenu; mimenu.agregar("Ver empleados registrados", '1'); mimenu.agregar("Agregar empleado a la planilla",'2'); mimenu.agregar("Modificar datos de empleado",'3'); mimenu.agregar("Eliminar empleado del registro",'4'); mimenu.agregar("Finalizar aplicacion",'s'); Sleep(1500); //pausa ejecucion por 1.5 segundos }//fin main 11. Guarde el cod. anterior bajo el nombre (GUIA11_ejemplo3.cpp) y compile el programa. Esta aplicación se ejecutara normalmente si se abre una ventana vacia durante 1.5 seg. y luego finaliza su ejecución automáticamente. 12. En el archivo GUIA11_adminCuentas.h, redacte un nuevo metodo para el struct empleado, denominado ingresardatos( ), que le permita a usted solicitar los valores de los campos del empleado que se almacenaran en ella. Cuide que el prototipo de este nuevo metodo se agregue después del prototipo del constructor (ubicado en el interior del struct) y la definición de este nuevo metodo hasta después de la definición del metodo constructor. 13. De manera similar al paso anterior, agregue al struct empleado otro metodo denominado verdatos( ), que permitirá imprimir en pantalla a los datos actuales de los campos del empleado, con un formato similar al ejemplo siguiente: Cristi Isabel Zelaya 15 años , $1500 Programacion de Algoritmos 9 Guía # 11: Archivos de texto 14. Ubique el cursor al final del cod. de esta librería, luego del comentario: //funciones generales (Definiciones). Redacte ahi a la siguiente pareja de funciones (recuperarCuentas y escribirCuentas), las cuales procesaran el almacenamiento y recuperación de la información de las empleados desde un archivo de bytes denominado (cuentas.DAT). Ubicar el siguiente segmento de código despues del comentario //Funciones generales (Definiciones) void recuperarCuentas(int &_totEmp ,empleado Em[]){ //acceso al archivo ifstream archi; //lectura modo binario ofstream archi2;//crear archivo int longi; //num byte final que contiene archivo _totEmp=0; //total empleados archi.open("cuentas.DAT",ios::binary); if(archi.is_open()){//Comprueba si archivo existe //Lee (Lcon acceso binario) a empleados del archivo archi.seekg(0,ios::end); //coloca cursor lectura en ultimo byte longi=archi.tellg(); //recupera num. del byte _totEmp=longi/sizeof(empleado); //determina total de empleados almacenados archi.seekg(0,ios::beg); //coloca cursor lectura al inicio for(int i=0;i<_totEmp;i++) archi.read((char *) &Em[i],sizeof(empleado)); archi.close(); }else{ archi2.open("cuentas.DAT",ios::out); //Crea archive archi2.close(); }//fin if }//fin funcion recuperarCuentas void escribirCuentas(int totEmp ,empleado Em[]){ //Abre archivo .DAT y reemplaza su contenido con el listado actual ofstream archi; //archivo (modo binario) a modificar archi.open("cuentas.DAT",ios::binary); archi.seekp(0,ios::beg); //coloca cursor escritura en byte inicial for(int i=0;i<totEmp;i++){ //ejecuta escritura datos en archivo binario archi.write((char*) (&Em[i]) , sizeof(empleado)); }//fin for i }//fin funcion escribirCuentas Luego, seleccione el encabezado de cada una de estas nuevas funciones y cópielas como prototipos, justamente después del comentario: //Funciones generales de manejo de cuentas Programacion de Algoritmos 10 Guía # 11: Archivos de texto 15. Guarde los cambios en la librería y retorne al cod. principal. Ubique el cursor una línea antes de invocar a Sleep ( ) y agregue ahí al siguiente segmento de código: //Lee los datos de empleados almacenados en archivo binario recuperarCuentas(totEmp,Emple); //ciclo principal do{ system("cls"); cout<<"MANTENIMIENTO DE PLANILLA MENSUAL\n\n"; mimenu.ver(); switch(mimenu.capturar( )){ case '1': break; case '2': break; case '3': break; case '4': break; default: salir=true; } if(salir) cout<<"\nEl programa finalizara ahora"; else{ cout<<"\n\nPresione cualquier tecla para regresar al menu"; getch(); } }while(!salir); escribirCuentas(totEmp,Emple); 16. Compíle el programa principal y ejecutelo. Si todo es correcto, se presentara el menú de manera continua. Confirme que la aplicación solo responde a las teclas ofrecidas en el menú, incluyendo Salir. 17. Retorne al código de la librería, para agregar correctamente a las funciones generales restantes. Y no debe olvidar redactar el respectivo prototipo de cada una. void imprimirCuentas(int totEmp ,empleado Em[]){ cout<<"\nLista de empleados registrados\n\n"; if(totEmp==0) cout<<"(aun sin registros)\n"; else{ cout<<"Tot. empleados: "<<totEmp<<endl; cout.setf(ios::left); Programacion de Algoritmos 11 Guía # 11: Archivos de texto cout<<"\n # "<<setw(25)<<"nombre"<<" Edad, cout.setf(ios::right); for(int i=0;i<totEmp;i++){ cout<<endl<<setw(3)<<i+1; Em[i].verdatos(); } } sueldo base ($)\n"; }//fin funcion imprimirCuentas void agregarCuenta(int &totEmp ,empleado Em[]){ cout<<"Agregando al empleado # "<<totEmp+1; Em[totEmp].ingresardatos(); totEmp++; //incrementa conteo empleados }//fin funcion agregarCuenta void eliminarCuenta(int &totEmp ,empleado Em[]){ int numEmp; //indice del empleado a borrar del arreglo cout<<"\nEliminando a un empleado\n\n"; if(totEmp==0) cout<<"(aun sin registros)\n"; else{ cout<<"Lista actual de empleados:\n"; cout.setf(ios::left); cout<<"\n # "<<setw(25)<<"nombre"<<" Edad, cout.setf(ios::right); for(int i=0;i<totEmp;i++){ cout<<endl<<setw(3)<<i+1; Em[i].verdatos(); } sueldo base ($)\n"; cout<<"\n\nDigite num de empleado a borrar: "; cin>>numEmp; numEmp--; //ajusta indice en conteo 0 removerposicion(totEmp,Em,numEmp); totEmp--; //reduce conteo de empleados }//fin if }//fin funcion eliminarCuenta void removerposicion(int &totEmp ,empleado Em[], int x){ //reemplaza posic [x] del vector con la posic [x+1] for(;x<totEmp-1;x++) Em[x]=Em[x+1]; }//fin funcion removerposicion Programacion de Algoritmos 12 Guía # 11: Archivos de texto 18. Guarde los cambios y retorne al cod. principal. Ubique el cursor luego de la sentencia case 1: Invoque ahí a la función imprimirCuentas( ) de esta manera: imprimirCuentas(totEmp,Emple); 19. De manera similar, en el interior de case 2, invoque a función agregarCuenta(). Haga lo mismo invocando a la función eliminarCuenta() desde case 4. En ambos casos, debe utilizar los mismos argumentos usados al llamar a imprimirCuentas. 20. Compile el programa principal y evalue el funcionamiento de la aplicación, utilizando las diferentes opciones del menú, incluyendo Salir, para luego volver a ingresar y confirmar que los registros de empleados son conservados. 21. Llame a su instructor para evaluar el procedimiento de esta practica. V. DISCUSION DE RESULTADOS Sobre el archivo de librería del ejemplo 3 del procedimiento, haga las modificaciones necesarias que permitan modificar los datos de un empleado elegido por el usuario. El programa principal deberá ser modificado invocando funciones creadas en la modificación solicitada en el párrafo anterior. VII. BIBLIOGRAFÍA • Programación en C++: Algoritmos, estructuras de datos y objetos. Joyanes Aguilar, Luis. No. De Clasificación 005.362 J88 2000. Editorial: MCGRAW HILL • Cómo Programar en C/C++. Deitel, Harvey M... No. De Clasificación 005.362 D325 1995 Editorial: PRENTICE HALL • Programación y diseño en C++: Introducción a la programación y al diseño orientado a objetos. Cohoon, James P; Davidson, Jack W. No. De Clasificación 005.362 C678 2000. Editorial: MCGRAW HILL. Programacion de Algoritmos 13