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