UNIVERSIDAD DON BOSCO FACULTAD DE ESTUDIOS TECNOLOGICOS ESCUELA DE COMPUTACION GUIA DE LABORATORIO Nº 11 CICLO 02-2013 Nombre de la práctica: Uso de archivos en C++ Lugar de ejecución: Laboratorio de Informática Tiempo estimado: 2:30 horas Materia: Introducción a la Programación I. Objetivos Que el estudiante sea capaz de: • • • • • Acceder a archivos de texto plano (.txt) con las funciones de la librería fstream.h de C++ Manejar las operaciones básicas con los flujos entrada (ifstream) y de salida (ofstream) de archivos Utilizar las funciones de manejo de archivos disponibles en librería fstream.h Escribir y leer datos de archivos de texto en C++ Utilizar funciones de conversión de tipos de datos proporcionados por librería stdlib.h II. Introducción Uso de archivos en C++ Un archivo 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. Archivos y streams C++ ve a cualquier archivo simplemente como una secuencia de bytes. Un archivo finaliza ya sea con una marca de end-of-file (eof) o en un byte determinado (tamaño del archivo) en una estructura de datos administrada por el sistema operativo (como un archivo en un directorio). Cuando un archivo se abre, se instancia un objeto archivo del tipo adecuado y un stream (también llamado nombre de archivo lógico) es asociado con este objeto. Para realizar estas acciones en C++ deben incluirse los archivos <iostream> y <fstream> ___________________________________________________________________________________________ 1 Jerarquía de clases stream Apertura de archivos Se define una variable (por ejemplo a r c h i v o ) para administrar el flujo de acceso al archivo (ofstream), por ej. ofstream archivo; Luego se invoca al método open con el parámetro apropiado según la siguiente sintaxis: archivo.open ("ejemplo.txt", ios::out | ios::app | ios::binary); Tipo acceso ios::in Descripción Abrir archivo para lectura ios::out Abrir archivo para escritura ios::ate Posición inicial: fin del archivo ios::app Cada salida se agrega al final del archivo ios::trunc Si el archivo ya existe se borra su contenido ios::binary Modo binario ___________________________________________________________________________________________ 2 Por ejemplo: ofstream archivo ("ejemplo.bin", ios::out | ios::app | ios::binary); Funciones de archivos Archivo.close(); Se encarga de vaciar los buffers que usa el archivo y cerrar acceso al archivo. Función e o f ( ) Para conocer si se ha llegado al final del archivo al leerlo. Opciones de estado Permiten conocer el estado de los flujos de datos del contenido de un archivo. bad(): Retorna true si ocurre una falla en las operaciones de lectura o escritura. Por ejemplo en caso de que tratemos de escribir en un archivo que no está abierto para escritura. fail(): Retorna true en los mismos casos que bad() y además en caso de que ocurra un error de formato, como tratar de leer un número entero y obtener una letra. eof(): Retorna true si el archivo abierto ha llegado a su fin. good(): Es el más genérico. Retorna false en los mismos casos en los que al llamar a las funciones previas se hubiera obtenido true. 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> ___________________________________________________________________________________________ 3 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; } Ejemplo de resultado del código anterior: Funciones de conversión de tipos de datos Gracias al registro de datos dentro de archivos de texto, se logra almacenar diferente tipo de información en los mismos, por ej.: fechas, nombres, descripciones, cantidades, distancias, etc. Como complemento a esta interacción con información almacenada en archivos, se necesita conocer un conjunto de funciones definidas en la librería stdlib.h, que permiten convertir texto en representaciones numéricas y viceversa. A continuación se describen las más utilizadas. Función itoa( ) char *itoa(int value, char * str, int Base); Convierte un valor entero (value) a una cadena caracteres (str), indicando opcionalmente a la base (Base) del sistema numérico en la que se expresara la respuesta, ej. int n; char buffer[33]; cout<<"ingrese un numero entero: "; cin>>n; itoa (n,buffer,10); cout<<"decimal es "<<buffer; itoa (n,buffer,16); cout<<endl<<"hexadecimal sera "<<buffer; itoa (n,buffer); //si ignora la base, asume que la misma es base 10 cout<<"decimal es "<<buffer; ___________________________________________________________________________________________ 4 Una salida del código anterior seria: ingrese un numero entero: 1750 decimal es 1750 hexadecimal sera 6d6 decimal es 11011010110 Function atoi int atoi (const char * str); Retorna la conversión a valor entero de una cadena de caracteres (s t r ) La cadena puede contener caracteres adicionales después de los que forman el número entero, que serian ignorados y no tienen ningún efecto sobre el comportamiento de esta función. Si el inicio de la secuencia de caracteres en str (que no sean espacios en blanco) no representan un número entero válido, o si no existe tal secuencia, ya sea porque str está vacío o sólo contiene espacios en blanco, la conversión no se realiza y la función devuelve cero (0). Ejemplo: int i; char buffer[256]; cout<<"Ingrese un numero entero: "; cin.getline(buffer, 256); //se captura entero como cadena de caracteres i = atoi (buffer); //convierte cadena buffer a tipo de dato entero i= i * 2; cout<<"\nEl doble del valor ingresado fue de "<< i; Una salida del código anterior podría ser: Ingrese un numero entero: 73 El doble del valor ingresado fue de 146 Function atof ( ) double atof (const char* str); Retorna un valor double de la conversión de un string. Comienza de izquierda a derecha, buscando la secuencia valida de una representación numérica. En caso de un carácter no valido, ignora la cadena restante. Ejemplo de uso: double n,m; double pi=3.1415926535; char buffer[256]; cout<<"Ingrese valor de grados sexagesimales: "; cin.getline(buffer,256); n = atof (buffer); //convierte cadena buffer a valor double m = sin (n*pi/180); //convierte numericamente a grados radianes cout<<"\nValor de "<<n<<" grados sexagesimales en radianes son "<< m; ___________________________________________________________________________________________ 5 Ejemplo de salida del código anterior: Ingrese valor de grados sexagesimales: 45 Valor de 45 grados sexagesimales en radianes son 0.707101 III. Requerimientos Nº 1 2 3 Cantidad 1 1 1 Descripción Compilador Dev-C++ Guía de Laboratorio #11 de Introducción a la Programación Memoria USB IV. Procedimiento 1. Preparar una carpeta denominada IPguia11proc_CARNET, en el cual guardara cada uno de los cpp’s del procedimiento y de los problemas a resolver. Creando un archivo de texto plano (.txt) 2. Crear un nuevo archivo de código fuente denominado guia11Ejemplo1 y digite el siguiente código: #include<iostream> using namespace std; //biblioteca de C++ que proporciona “funciones” y operadores //para el manejo de archivos #include<fstream> #include<stdlib.h> main(){ ofstream archivo; // crea un objeto de la clase ofstream char nom[25];//nombre a solicitar a usuario cout<<"\tDemostracion acceso a un archivo de texto\n"; //Abre el archivo en forma de escritura (ios::out) archivo.open("agenda.txt",ios::out); //comprueba si archivo fallo al querer crearlo/abrirlo if (!archivo){ cout<<"No se puede abrir el archivo" <<endl; }else{ cout<<"Acceso correcto para escritura del archivo\n"; cout<<"Escriba 1er nombre a registrar en archivo:"; cin.getline(nom,25); //escribe nombre en nuevo archivo archivo<< "1er nombre: " << nom <<endl; cout<<"Ahora escriba 2do nombre:"; cin.getline(nom,25); //escribe nombre en nuevo archivo archivo<< "2do nombre: " << nom <<endl; ___________________________________________________________________________________________ 6 archivo.close(); //cierra el manejador archivo cout<<"!!!!Los datos fueron agregados!!!"<<endl; } system("pause"); }//fin main 3. Ejecute el programa anterior. Observe que la aplicación le indica que se ha logrado acceso al archivo para escritura. Por ser la 1er vez que ejecuta el programa, ofstream crea el archivo agenda.txt. Minimice la ventana del compilador y observe contenido de su carpeta de trabajo. Se ha creado el archivo en la misma carpeta donde se ha generado el .exe del cod.fuente de C++ actual. Ingrese al archivo de texto agenda.txt para confirmar el contenido del archivo y cierre la ventana del editor de texto 4. Vuelva a ejecutar el programa y este le solicita nuevamente 2 nombres para escribir en archivo. Abra nuevamente el archivo agenda.txt y compare su contenido actual con el de la 1er ejecución. ¿El contenido es de igual contenido o diferente? 5. 6. Cerrar ventana del archivo agenda.txt y retornar al editor de C++. Cambia el nombre del archivo “ a g e n d a . t x t ” por el de “ c : \ a g e n d a . t x t ” , para intentar crear el archivo de texto en la raíz del sistema de archivos del disco duro. Ejecutar de nuevo el programa y analice el resultado 7. Retorne al cod.fuente del programa y restaure el nombre del archivo a crear como “ a g e n d a . t x t ” . Además, reemplazar el parámetro resaltado i o s : : o u t por el del Modo agregar archivo (i o s : a p p ). 8. 9. Ejecutar nuevamente el programa e indicar 2 nuevos nombres. Retorne de nuevo al contenido del archivo agenda.txt y compare los resultados con las ejecuciones anteriores. Accediendo al contenido de un archivo de texto plano (.txt) 10. Guardar los cambios del archivo cpp actual y hacer una copia del mismo bajo el nombre guia11Ejemplo2. De este nuevo cpp, borre todo el contenido de la función main, excepto la última función system(“pause”). Ahora hará las pruebas de acceso a un archivo en modo Lectura, para obtener la información almacenada en un archivo de texto ya existente. 11. Digite el siguiente código entre las llaves { } de main del cpp guia11Ejemplo2: ___________________________________________________________________________________________ 7 ifstream archivo2;//variable para acceso de lectura a un archivo char nombrearchivo[50]; //nom archivo a leer, dado por usuario char lineatexto[100];//una linea texto copiada desde archivo a leer int cl=0; //contador lineas leidas de archivo cout<<"Indique nombre de archivo a acceder para lectura: "; cin.getline(nombrearchivo,50); //intenta abrir archivo nombrearchivo para lectura archivo2.open(nombrearchivo,ios::in); if(!archivo2){ cout<<"-> Error, archivo imposible de abrir\n"; }else{ cout<<"-> Acceso exitoso para lectura de archivo "<< nombrearchivo<<"\nSu contenido lineaxlinea:\n"; //Comienza proceso lectura del archivo //repetira lectura solo cuando no se alcance final contenido while(!archivo2.eof()){ archivo2>>lineatexto; cl++; cout<<cl<<":\t"<<lineatexto<<endl; }//fin while cout<<endl; archivo2.close();//cierra acceso archivo de lectura }//fin if inicial 12. Guardar los cambios y compile el programa. Ante la solicitud del nombre del archivo, digitar miagenda.txt. El programa indicara que el archivo de no pudo abrir. 13. Repita el paso anterior, pero digite el nombre del archivo de texto ya existente (agenda.txt) Del resultado devuelto, ¿Qué es lo que realmente esta leyéndose del archivo con la línea de código resaltada a r c h i v o 2 > > l i n e a t e x t o ? 14. Comente la línea resaltada del paso anterior e inserte en su lugar este comando: archivo2.getline(lineatexto,100); 15. Ejecute de nuevo el programa para leer contenido de archivo agenda.txt. ¿Funciono esta vez la lectura de las líneas del archivo?, ¿Hay algún problema en el resultado visto en pantalla? Almacenando/Recuperando información de aplicaciones hacia/desde archivo de texto plano (.txt) 16. Crear un nuevo archivo cpp, para guardarlo bajo el nombre guia11Ejemplo3. En este ejemplo, se permite el ingreso de los datos de un total de n cuentas de ahorro, para luego ir agregándolos dato por dato hacia un archivo de cuentas (llamado cliente.txt). #include <iostream> #include <fstream> using namespace std; main(){ //datos cuenta ahorro ___________________________________________________________________________________________ 8 int cuenta; char nombre[15]; char apellido[15]; double saldo; int n,i; cout<<"Aplicacion para la creacion de registros bancarios\n\n"; //ofstream abre el archivo en forma de escritura // ios::app agrega los datos al final del archivo ofstream archivoclientessalida("cliente.txt", ios::app); //Finaliza programa si no se puede crear el archivo if (!archivoclientessalida){ cout<<"No se puede abrir el archivo" <<endl; exit(1);//Finaliza main, sin ejecutar resto del codigo } cout<<endl<<"Digite el numero de clientes a ingresar: "; cin>>n; i=1;//inicia con empleado 1 //Lee cuenta, nombre y saldo con cin while (i<=n) { cout<<"\n\n--> Datos de Cuenta (#"<<i<<"):\n"; cout<<"\nNumero de cuenta ??\t";cin>>cuenta; cout<<endl<<"Nombres ??\t"; fflush(stdin); cin.getline(nombre,15); cout<<endl<<"Apellidos ??\t"; fflush(stdin); cin.getline(apellido,15); cout<<endl<<"Saldo inicial($) ??\t ";cin>>saldo; //Escribe variables anteriores en el archivo de salida archivoclientessalida<<cuenta<<endl<< nombre<<endl<<apellido<<endl<<saldo<<endl; i++;//proximo empleado a registrar } //fin de while i //cierra acceso archivo de escritura archivoclientessalida.close(); cout<<"\nSE TERMINO DE AGREGAR DATOS AL ARCHIVO\n"; system("pause"); }//fin main 17. Compilar y ejecutar el programa anterior. Ingresar un total de 2 cuentas bancarias y luego ingresar los respectivos datos de c/u. Al finalizar el programa, localizar archivo cuentas.txt en la carpeta de trabajo y revisar su contenido 18. Repetir el paso anterior, pero con datos de nuevas cuentas bancarias. Después revisar nuevamente el archivo de texto cuentas.txt y confirmar que la información se va acumulando al final. 19. Crear un nuevo archivo cpp, para guardarlo bajo el nombre guia11Ejemplo4. En este último ejemplo, se recupera la información sobre las cuentas bancarias registradas en el archivo de texto cuenta.txt (creadas con el programa del ejemplo anterior). #include <iostream> #include <fstream> #include <iomanip> using namespace std; ___________________________________________________________________________________________ 9 #include <conio.h> main(){ //datos de una cuenta ahorro char linea[10]; int cuenta; char nombres[25]; char apellidos[25]; double saldo; // ifstream abre el archivo en modo -lectura ifstream archivoclientesentrada("cliente.txt",ios::in); //sale del programa si ifstream no puede abrir el archivo if (!archivoclientesentrada) cout<<"no se puede abrir el archivo" <<endl; else{ cout<<"\tLISTA DE CUENTAS BANCARIAS REGISTRADAS\n\n"; cout.setf(ios::fixed); cout.precision(2); //prepara encabezado de tabla a mostrar cout<<"#Cuenta"<<setw(17)<<"Nombre"<<setw(25)<< "Apellido"<<setw(16)<<"Saldo($)"<<endl; // Lista cada registro en el archivo //verifica que no ha llegado al final del archivo while (!archivoclientesentrada.eof()){ /*se captura del archivo los datos, para ser almacenados en las variables del programa*/ archivoclientesentrada.getline(linea,10); cuenta=atoi(linea);//convierte cadena texto en valor entero (int) if(cuenta==0) //ya no hay cuentas que mostrar break;//finaliza while archivoclientesentrada.getline(nombres,25); archivoclientesentrada.getline(apellidos,25); archivoclientesentrada.getline(linea,9); saldo=atof(linea);//convierte cadena texto en valor float //muestra resultados en pantalla cout<<setw(5)<<cuenta<<setw(25)<<nombres<<setw(25)<< apellidos<<setw(10)<<saldo<<endl; }//fin de while }//fin de if archivoclientesentrada.close(); cout<<endl; system("pause"); }//fin main 20. Compilar y ejecutar el programa. Confirmar que los datos mostrados en la consola son los mismos almacenados en el archivo de texto cliente.txt. ___________________________________________________________________________________________ 10 PROBLEMAS A RESOLVER: Elabore el código fuente de C++ que solucionen a cada uno de los problemas a continuación: Problema1.cpp Crear un programa que pida el salario base de n empleados. Calcule el salario neto de c/empleado, tomando en cuenta que se le descuenta el 3% de ISSS y $60 por un seguro contra accidentes. Almacenar en un archivo de texto denominado planilla.txt a la siguiente información: + Información de cada uno de sus empleados: nombres, código (formado por las 2 letras iniciales de su 1er nombre y las 2 letras iniciales de su 1er apellido), su salario base y salario neto. + Monto de la planilla a pagar, así como el sueldo neto promedio general Importante: Los registros deben ser almacenados en el archivo, ordenados por el 1er apellido de los empleados. El contenido del archivo debe quedar en un formato listo para imprimir, simulando una “tabla” (evaluar para ello al ejemplo guia11Ejemplo4) ___________________________________________________________________________________________ 11