martes, 10 de enero de 2017

ENTRADA Y SALIDA POR ARCHIVOS

CAPÍTULO 9      ENTRADA Y SALIDA POR ARCHIVOS 




La entrada y salida por archivos es uno de los temas más importantes para la programación, es necesario para poder programar desde una pequeña agenda hasta una completa base de datos, pero antes de entrar de lleno a este tema, y aprovechando los conocimientos adquiridos hasta el momento, quiero mostrar el uso de la memoria dinámica. MEMORIA DINÁMICA Hasta el momento no contamos con una forma de “administrar” la memoria utilizada en nuestros programas, cuando declaramos una variable se asigna memoria para almacenar datos dentro de ella, y ésta no se destruye hasta que termina el bloque en el que fue declarada, se crea y se destruye cada que se pasa por ese bloque, quizá puede parecer poco importante, pero cuando se cuentan con grandes cantidades de datos, es necesario tener un mejor control de lo que se pone en memoria. Una de las formas en que podemos asegurarnos que una variable declarada dentro de un bloque no sea borrada al término de éste, es mediante la utilización del calificador static. De ésta manera, la variable perdurará hasta el término de todo el programa. static tipo_variable mi_variable; 96 Pero en algunos casos esto nos será insuficiente, vamos a necesitar “destruir” variables antes de terminar el programa, para hacer esto contamos con los operadores new y delete. Se puede utilizar el operador new para crear cualquier tipo de variables, en todos los casos devuelve un puntero a la variable creada. En el momento en que se quiera borrar esta variable deberemos utilizar el operador delete, todas las variables creadas mediante el operador new deben de ser borradas con el otro operador. En el siguiente ejemplo utilizaremos estos dos operadores para mostrar sus ventajas. #include int main(){         char *cadena2;         int fincontador=10;         cout<<"programa de prueba"<>respuesta;         char cadena[3]="hi";         if(respuesta==1){                 int LongCad;                 cout<<"variable creada"<>LongCad;                 cadena2=new char[LongCad];                 cout<<"escribe: "< #include const int NumMaterias=11; struct alumno {         int boleta, semestre;         int calificaciones[NumMaterias];         void constancia(alumno * este){ 98                 cout<<"constancia impresa"<boleta;                 cout<semestre<calificaciones[i]<calificaciones[i]=0;                 este­>boleta=0;                 este­>semestre=0;         } }; int main(){         alumno *alan =new alumno;         alan­>inicia(alan);         cout<<"alan creado"<boleta=2005630170;         alan­>semestre=5;         alan­>constancia(alan);         delete alan;         alumno *alfonse=new alumno;         alfonse­>inicia(alfonse);         alfonse­>constancia(alfonse);         delete alfonse;         alan­>constancia(alan);         cin.get();         return 0; } Como en el ejemplo anterior, declaramos una variable de tipo apuntador (apuntador a alumno) y luego le asignamos espacio en memoria. Cuando se invoca a la función miembro “inicia”, se envía como argumento el nombre del apuntador, y como este contiene una dirección de memoria, pues entonces la función que lo recibe esta preparada para recibirlo y manejarlo adecuadamente con el operador flecha. 99 Note que después de la destrucción de la variable “alan” se crea otra de nombre “alfonse” que también se destruye, y posteriormente se invoca de nuevo a la función “constancia” de “alan”, dependiendo del compilador utilizado puede haber distintos resultados, pero es lógico que no se obtendrá lo que deseamos porque esa variable ya no existe. ARCHIVOS Para empezar con el manejo de archivos es necesario recordar el concepto de flujo, el cual se define como un dispositivo que consume o produce información. En nuestros programas hechos hasta el momento hemos utilizado los flujos estándar cin, cout y cerr, el resto de los flujos que se deseen deberán ser creados por el programador. Todos los flujos se comportan de forma análoga, independientemente del dispositivo que se trate. Para poder usar un flujo estándar basta con incluir la biblioteca iostream.h como lo hemos hecho hasta ahora. Cuando decidimos utilizar la función cin.get() no sabíamos exactamente el porque de la utilización del punto(.), ahora que hemos visto un poco el concepto de estructura podemos decir que se trata de la invocación a una función miembro del flujo cin. Sí, el flujo es un objeto, viéndolo desde la perspectiva de las estructuras y no precisamente de las clases como debería de ser, se trata de un tipo de dato que contiene variables y funciones que pueden ser invocadas. A lo largo de este capítulo hablaremos de los flujos como estructuras, y no como clases para tener una mejor idea de lo que se tratan. Las estructuras (en realidad clases) para la entrada y salida de datos tienen un orden jerárquico, en ellas existe la herencia que básicamente consiste en que una de orden 100 inferior obtiene las mismas variables y funciones que la de orden mayor, además de que puede agregar más. Para poder trabajar los ficheros como flujos es necesario incluir la librería fstream.h, y según la utilización que queramos dar a este fichero (lectura o escritura) deberemos declarar el tipo de flujo. Para crear un archivo de salida declaramos una variable de tipo ofstream, el cual ya está declarado dentro de nuestra librería. Es mejor ver un ejemplo de base. #include int main(){         ofstream archivo;         archivo.open("miarchivo.txt");         archivo<<"hola desde este archivo\n";         archivo<<"ya he escrito algo\n";         archivo.close(); } Aquí declaramos a “archivo” como variable tipo ofstream, y posteriormente utilizamos su función miembro open para asociarla a un archivo, se pude asociar directamente en la declaración de la siguiente manera: 101 ios istrstream istream istream_withasign ifstream ostream ofstream ofstream_withasign ostrstream iostream fstream strstream stdiostream ofstream archivo(“miarchivo.txt”); Tanto la primera como la segunda forma admiten un segundo argumento que especifica el modo de apertura de un archivo. Los modos disponibles se muestran en la siguiente tabla y pueden ser utilizados incluyendo la librería iostream.h. ios::app Se escribe al final de archivo ios::out El archivo se abre para escritura ios::trunc Si el archivo existe se eliminará su contenido ios::in El archivo se abre para lectura, el archivo original no será modificado ios::binary El archivo se abre en modo binario Tabla 12 Modos de apertura de archivo Con el archivo creado en el ejemplo anterior utilizaremos el siguiente programa para escribir al final de él. #include #include int main(){         ofstream archivo("miarchivo.txt", ios::app);         archivo<<"hola desde este archivo de nuevo\n";         archivo<<"ya he escrito algo de nuevo\n";         archivo.close(); } El método para abrir un archivo en modo lectura es muy similar, pero en este caso utilizaremos ifstream. Para tener el control del fichero, aparte de conocer los modos de apertura de un archivo, debemos de conocer el delimitador, así como en las cadenas existe el carácter de fin de cadena('\0'), en los archivos está el fin de archivo (EOF). El siguiente programa lee caracteres de un archivo y los imprime en pantalla hasta llegar al fin de éste. 102 #include #include int main(){         char caracter;         ifstream archivo("miarchivo.txt", ios::in);         while(!archivo.eof()){                 archivo.get(caracter);                 cout< #include int main(){         char caracter;         ifstream archivo("miarchivo2.txt", ios::in);         if(archivo){                 while(!archivo.eof()){                         archivo.get(caracter);                         cout< #include #include int main(){         char texto_preg[300],texto_resp[300],*compara=NULL;         ifstream archivo("arch.txt", ios::in);         if(!archivo){                  cerr<<"error al abrir el archivo";                 return 1;         }         cout<<"* hola"< ";         cin.getline(texto_resp,290);         while(texto_resp[0]!='\0'){         archivo.seekg(0);         do{                 archivo.getline(texto_preg,290);                 compara=strstr(texto_resp,texto_preg);                 if(archivo.eof()){              cout<<"* no se contestar, dimelo por favor"< ";              archivo.getline(texto_preg,290);         cout<<"* "< ";         cin.getline(texto_resp,290);         }         archivo.close();         return 0; } Se trata de un simple programa de conversación, donde el elemento principal es el archivo “arch.txt”, el cual contiene una conversación en él: 105 hola como estas? bien que haces? nada pues ponte a hacer algo, a que te dedicas? estudio y que estudias? informatica ha que bueno!!, de donde eres? ixtapaluca que interesante, hay algo que quieras preguntarme? como te llamas? acaso eso importa? como te llamas pregunta de nuevo El programa inicia abriendo el archivo en modo lectura, si existe un error el programa termina. Empieza su conversación diciendo “hola”, y espera a que el usuario responda, atrapa su respuesta y la guarda en una cadena, si tecleó algo que no fuera simplemente un enter entonces continua dentro del bucle. Se posiciona al inicio del archivo, y, dentro de otro bucle, lee la cadena de caracteres del archivo con un máximo de 290 caracteres y la almacena en “texto_preg”. Utilizando la función strstr() de la biblioteca string.h, compara la cadena introducida por el usuario con la cadena que acaba de leer del archivo, la función strstr() devuelve un apuntador a la primera localización de la cadena “texto_preg” en “texto_resp”, si no se encuentra devuelve NULL. Si se ha llegado al final del archivo, es decir, no se encontró que contestar, pide a la persona que le diga que debe de contestar, entonces cierra el archivo y lo vuelve a abrir pero esta vez en modo de escritura para añadir la pregunta del usuario con su respectiva respuesta, luego cierra el archivo de salida y lo abre en modo de lectura de nuevo. 106 Estos pasos de buscar y, si no encuentra entonces preguntar, continuarán mientras no se encuentren coincidencias entre lo escrito y lo que está dentro del archivo. Después, continuando con el bucle de mayor nivel, vuelve a leer del archivo una cadena de caracteres, y empieza la conversación de nuevo. Para terminar el programa simplemente el usuario debe teclear enter sin ningún otro caracter. Como ya se habrá dado cuenta, la parte principal de este programa es el archivo, en él está la base de la conversación, y si se quiere una plática más amena pues hay que modificar el archivo y aumentar su repertorio de respuestas. Note que al final del archivo hay una linea en blanco para el correcto funcionamiento del programa. 

No hay comentarios:

Publicar un comentario