Professional Documents
Culture Documents
Programacin 2 / C++
Eduardo Serna-Prez
Archivos en C++
Los archivos son empleado para retener permanentemente grandes cantidades de datos en
dispositivos de almacenamiento secundario como discos o memorias flash, en esta unidad
veremos la manera de procesar archivos mediante instrucciones de flujo de datos empleado en
C++. Consideraremos el manejo de archivos, tanto de acceso secuencial, como aleatorio (binario).
2.1
En C++, al igual que en C, existen bsicamente 2 tipos o clases de archivos: acceso secuencial y
acceso binario, esta diferencia radica principalmente en la manera cmo se accede (lee y escribe)
la informacin contenida en ellos. La manera en como se trabajara con el archivo es especificado
al momento de la apertura.
Acceso Secuencial (de texto): Estn relacionados con el proceso de textos y/o el intercambio
de secuencias de caracteres entre el programa y el archivo. Las lneas de caracteres pueden
terminar en \n. Es posible realizar un formato libre, lo que hace que pueda no haber una
correspondencia exacta entre los caracteres que son escritos/ledos por el sistema y los
existentes en el archivo.
Acceso Binario (aleatorios): Se caracterizan porque existe una correspondencia exacta entre
los caracteres que componen el flujo (entrada/salida) y los que aparecen en el archivo. Suelen
ser mas sencillos de manipular para el caso de simular alguna base de datos.
Los archivos de texto suelen ser ms utilizados con fines de reporte o para la manipulacin de
datos muy sencillos que no implican un alto movimiento de operaciones (altas, bajas, cambios,
consultas). Por otro lado los archivos binarios suelen ser muy utilizados para crear bases de datos
primitivas, debido a que el manejo de operaciones se vuelve muy sencillo, aunque
desafortunadamente suelen consumir muchos recursos.
2.2
C++ ve a cada archivo simplemente como una secuencia de bytes. Todo archivo termina con un
marcador de fin de archivo. Cuando se abre un archivo, se crea un objeto y se asocia un flujo con
ese objeto. Los flujos asociados con ellos proporcionan canales de comunicacin entre un
programa y un archivo o dispositivo en particular. De alguna manera el manejo de archivos es muy
similar al empleado por los objetos de flujo de entrada y salida estndar (cin, cout).
Para realizar el procesamiento de archivos en C++ se deben incluir los archivos de encabezado
<iostream.h> y <fstream.h>. La clase fstream incluye las definiciones para las clases ifstream y
ofstream, que manejan, respectivamente, el flujo de entrada y salida de datos a un archivo. La
clase fstream permite crear archivos de salida / entrada, en funcin del modo de apertura.
Los archivos se abren mediante la creacin de objetos de esa clase de flujo, las cuales se derivan
(heredan) de las clases istream, ostream e iostream. Por lo tanto todas las funciones miembro,
operadores y manipuladores que se describieron en la unidad 2, pueden aplicarse al flujo de
archivos.
C++ no impone una estructura sobre un archivo, por tanto no existe el concepto de registro. Debido
a esto es responsabilidad del programador estructurar los archivos para satisfacer las necesidades
de la aplicacin final.
2.3
Programacin 2 / C++
Eduardo Serna-Prez
Archivos secuenciales
Los archivos secuenciales suelen ser la manera ms sencilla de manipulacin de datos, debido a
que su mecanismo se basa en la transferencia libre de datos al archivo, por lo que el diseo o
formato del mismo queda bajo la responsabilidad del programador, de manera que el ingreso y
salida de datos puede no siempre ser correcta. De tal forma suelen ser muy utilizados como una
herramienta para emitir reportes o para el manejo de pequeos bancos de datos.
2.3.1
Para manejar archivos es necesario crear objetos de la clases de flujo ifstream, ofstram y fstream.
Para crear archivos de salida es necesario primero crear un objeto ofstream, posteriormente
empleamos el mtodo open, que crean el vinculo del objeto con el archivo, indicando el nombre del
archivo y el modo de apertura que emplearemos.
A continuacin se describe una tabla con los modos de apertura para archivos en C++.
Modo
ios::app
ios:ate
ios::in
ios::out
ios::trunc
ios::binary
Descripcin
Abre el archivo en modo append (agregar), y as poder anexar datos.
Al abrir el archivo se posicionara al final
Abre un archivo para lectura (entrada).
Abre un archivo para escritura (salida).
Descarta el contenido del archivo en caso de que exista.
Abre un archivo en modo binario.
Podemos entonces declarar el objeto y ejecutar el mtodo de apertura indicando el nombre del
archivo y el modo de apertura con el que trabajaremos, como se muestra a continuacin. Resulta
obvio pensar que si creamos un objeto ofstream no es necesario indicar el tipo de apertura ya que
inevitablemente ser de salida, por lo que se omite el modo de apertura.
fstream archivo;
ofstream archivo;
archivo.open(prueba.txt,ios::out);
archivo.open(prueba.txt);
Ambas maneras previas son correctas. Se recomienda ms emplear la clase fstream para
construir objetos tipo archivo, en conjunto con los modos de apertura.
Al igual que se hace en C, en C++, los archivos deben de ser verificados posterior a su apertura
para asegurarse de que no ocurrieron errores de apertura, para ello se emplea el operador ! , el
operador devolver 0 en caso de no encontrarse error alguno.
2.3.2
Programacin 2 / C++
Eduardo Serna-Prez
La escritura de datos resulta ser un asunto muy sencillo debido a que lo nico que se necesita es
enviar el flujo de salida a un dispositivo, de la misma manera que lo hacemos con cout, solo que
aqu el dispositivo de salida estndar ser sustituido por el objeto de tipo archivo. Y de la misma
manera que lo hacemos con cout, emplearemos los operadores de insercin de flujo << para
depositar los datos en el dispositivo (archivo).
A continuacin se muestra un ejemplo sencillo donde se crea un archivo de texto donde se ingresa
la informacin relativa al numero de cuenta, nombre y monto de un registro arbitrario:
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
fstream archivo; // crea un objeto de tipo file-stream
// crea un archivo al que es posible agregar datos
archivo.open("clientes.txt",ios::out|ios::app);
if ( !archivo ) { // verifica el vinculo con el archivo
cerr << " No se pudo abrir el archivo " << endl ;
cin.get();
return 1; // termina el programa
}
cout << "dame la cuenta, nombre y monto\n cuenta en 0 termina\n ";
bool respta = true; /* variable booleana */
// datos del cliente
int cuenta;
char nombre[30];
float monto;
while( respta ){ // mientras sea cierta respta
cout << "cuenta :";
cin >> cuenta;
if (cuenta == 0) break; //Si cuenta = 0 termina el ciclo while
cout << "Nombre :";
cin >> nombre;
cout << "Monto :";
cin >> monto;
// manda el flujo de salida al archivo
archivo << cuenta << " " << nombre << " "<< monto << endl;
cout << "? ";
}
archivo.close(); // cierra el archivo
return 0;
}
Las variables cuenta, nombre y monto, son enviados al archivo mediante el operador de flujo de
insercin << hacia el objeto (archivo) de tipo fstream, al final se incluye el manipulador endl que
permite hacer un salto de lnea para separar cada registro por filas. Finalmente, al ya no integrar
mas registros se emplea el mtodo close, para cerrar el vinculo con el archivo.
Programacin 2 / C++
Eduardo Serna-Prez
2.3.3
Al igual que lo hicimos con la creacin e insercin de datos, para la lectura y extraccin de datos es
necesario crear un objeto de tipo fstream.
Apertura con objeto fstream
fstream archivo;
ifstream archivo;
archivo.open(prueba.txt,ios::in);
archivo.open(prueba.txt);
Ambas maneras previas son correctas. Se recomienda mas emplear la clase fstream para
construir objetos tipo archivo, en conjunto con los modos de apertura.
fstream archivo(prueba.txt, ios::in);
A continuacin mostramos un programa que resulta ser la contraparte del anterior, este permite
extraer y mostrar los registros contenidos en el archivo.
#include <iostream>
#include <fstream>
using namespace std;
int main ()
{
fstream archivo; // crea un objeto de tipo file-stream
// abrimos el archivo en modo de lectura
archivo.open("clientes.txt",ios::in);
if ( !archivo ) { // verifica la existencia del archivo
cerr << " No se pudo abrir el arcivo " << endl;
cin.get();
return 1; // termina el programa
}
int cuenta; // datos del cliente
char nombre[30];
float monto;
// contamos el numero de registros
int x = 0; // extraemos los datos del archivo
while( archivo >> cuenta >> nombre >> monto )
x++; // contabilizamos
cout << "Existen " << x << " registros en el archivo\n"<<endl;
archivo.clear(); // restablece el eof para la sig entrada
archivo.seekg( 0 ); // se mueve al inicio del archivo
Programacin 2 / C++
Eduardo Serna-Prez
2.3.4
Programacin 2 / C++
Eduardo Serna-Prez
Programacin 2 / C++
Eduardo Serna-Prez
#include <iostream>
#include <fstream>
using namespace std;
/*
La funcion cuenta recibe como argumento un puntero a char
para relacionado con el nombre del archivo, y regresa el
numero de lineas existentes en dicho archivo
*/
int cuenta(char *);
int main()
{
cout << "las lineas son " << cuenta("ejemplo.txt");
cin.get();
return 0;
}
int cuenta(char *nombre)
{
fstream archivo(nombre,ios::in); // crea el vinculo con el archivo
int cont = 0;
char cadena[80];
archivo.getline( cadena, 80 ); // extrae una linea del archivo
while ( ! archivo.eof() ){
cont++; // contabiliza las lineas
archivo.getline( cadena, 80 ); // extrae una linea del archivo
}
archivo.close();
return cont;
}
2.4
Los archivos de acceso aleatorio (binarios) resultan ser la manera ms practica de almacenar
informacin (registros), debido principalmente a que es muy sencillo ubicar los registros dentro del
archivo, ya que esa bsqueda se realiza en clculos de desplazamiento de bytes, por lo que es
sencillo ubicar un registro.
2.4.1
Para los archivos de acceso aleatorio es necesario crear una estructura (cascaron) disponible que
nos permita tener una cantidad especifica de espacios definidos para los registros.
Para el caso de los archivos binarios se recomienda incorporar la etiqueta de modo de apertura
ios::binary, que especifica un modo de apertura de archivo binario. Adems existen dos mtodos
heredados de iostream, read y write.
El mtodo write nos permite enviar el flujo de salida hacia el objeto de tipo archivo (localidad de
memoria). La funcin espera un primer argumento de tipo char * que corresponde a los datos
(registro) que sern almacenados en el archivo. El segundo es un argumento entero de tipo size_t
que especifica el numero de bytes ( sizeof ) a escribir.
Programacin 2 / C++
Eduardo Serna-Prez
Para mostrar el uso del mtodo write, asumiremos el siguiente cdigo, recuerde que el uso de
estructuras en archivos binarios es muy habitual y facilita la manipulacin de los mismos datos:
Suponga que se tiene una estructura llamada cliente
struct cliente
{
int cuenta;
char nombre[30];
float monto;
};
creamos una variable tipo (registro) cliente donde recogemos la informacin referente al registro,
en este caso el nombre esta vaco, la clave y el registro estn inicializados a 0
cliente registro = {0,"",0}; // registro en balco
una vez capturada la informacin, el registro es enviado al objeto archivo con la funcin write.
Podemos emplear cualquiera de sus 2 variantes, ambas en realidad son operaciones de
conversin de tipos ( cast ), slo que la segunda manera resulta ser ms adecuada, debido a que
es un operador de conversin de tipo incorporado en compiladores modernos de C++.
archivo.write((char *)®istro, sizeof(cliente));
Programacin 2 / C++
Eduardo Serna-Prez
2.4.2
Para este caso, emplearemos el mtodo seekp en combinacin con write para almacenar los
datos en localidades exactas del archivo. La funcin seekp establece el apuntador de posicin de
archivo en una localidad especifica del archivo y luego write enva los datos a la salida.
El primer argumento de seekp indica el desplazamiento en bytes a partir del segundo argumento;
es decir, el inicio del archivo (ios::beg), el fin del archivo (ios::end) o la posicin actual (ios::cur)
dentro del archivo.
Para el caso del primer argumento es muy comn emplear el campo llave (entero) en combinacin
con el operador sizeof, debido a que se realiza una simple multiplicacin para determinar el
desplazamiento (relativo) de bytes dentro del archivo, por eso es muy habitual restarle uno al
campo llave. Es decir, por ejemplo, para el registro 1 se ubica la posicin 0, que implica cero
desplazamientos en bytes dentro del archivo.
archivo.seekp( (llave -1) * sizeof(estructura) , ios::beg);
Es posible tambin emplear la funcin seekp sin el segundo argumento, lo que implica un
desplazamiento absoluto, es decir desde el inicio.
archivo.seekp( (llave -1) * sizeof(estructura) );
En el ejemplo se muestra como ingresar datos (altas) a un archivo binario, observe como primero
es necesario posicionarse en una localidad especifica empleando el mtodo seekp y despus
empleamos el mtodo write para escribir la estructura con informacin en el archivo.
#include <iostream>
#include <fstream>
using namespace std;
struct cliente{
int cuenta; // campo llave
char nombre[30];
float monto;
};
int main ()
{
fstream archivo; /* crea un objeto de tipo file-stream */
/*apertura de archivo sin remplazo en modo binario de salida */
archivo.open("clientes.dat", ios::binary|ios::in|ios::out);
Programacin 2 / C++
Eduardo Serna-Prez
2.4.3
La funcin read de istream introduce un numero especifico de bytes desde la posicin actual en el
flujo especificado hacia el objeto, para ello emplearemos la misma tcnica utilizada con write,
empleando el operador de conversin de tipo (cast).
El primer parmetro de read indica la estructura en donde ser almacenada el registro que ha sido
ledo del archivo. El segundo argumento es el tamao en bytes que sern ledos del archivo. Tome
en cuanta que al igual que con write, read necesita hacer un conversin de tipo a char *, por lo
que se emplea el operador de conversin de cualquiera de las dos formas.
archivo.read( (char *)®istro, sizeof(cliente));
archivo.read(reinterpret_cast<char *>(®istro), sizeof(cliente));
Al igual que con la escritura emplebamos seekp, en la lectura es necesario emplear el mtodo
seekg en combinacin con read, para realizar la lectura de datos en una posicin especifica.
archivo.seekg( (llave -1) * sizeof(estructura) , ios::beg);
Recuerde que tambin es posible omitir el segundo argumento, en cuyo caso resultara un
desplazamiento absoluto.
10
Programacin 2 / C++
Eduardo Serna-Prez
11
Programacin 2 / C++
Eduardo Serna-Prez
float monto;
};
int main ()
{
fstream archivo; /* crea un objeto de tipo file-stream */
/* apertura de archivo en modo binario de lectura */
archivo.open("clientes.dat", ios::binary|ios::in);
if ( !archivo ) { // verifica la existencia del archivo
cerr << " No se pudo abrir el archivo " << endl;
return 1; // termina el programa
}
cliente registro;
cout << "Datos del los cliente...\n";
archivo.read((char *)®istro, sizeof(cliente));
while( !archivo.eof() ){
if (registro.cuenta != 0)
cout << "cuenta " << registro.cuenta << " Nombre-> " <<
registro.nombre << " Monto-> " << registro.monto << endl;
archivo.read((char *)®istro, sizeof(cliente));
}
archivo.close(); // cierra el archivo
cin.get();
return 0;
}
2.4.4
Debido a que la informacin no es constante, es necesario emplear una tcnica que nos permita
modificar su contenido, es decir, en ocasiones tenemos registros que necesitan ser modificados en
algn campo como el domicilio, el saldo, la edad entre otros e incluso existen registros que deben
ser removidos de un archivo debido a que ya no son utilizados u obsoletos.
Para ello es necesario hacer uso de la modificacin de datos, la manera mas sencilla de realizarlo
con archivos binarios es abrir los archivos en modo de lectura/escritura. A continuacin mostramos
el cdigo de un programa que permite hacer remocin de registros (bajas).
Para realizar bajas de registros es necesario hacer una lectura de datos para verificar si la
informacin que se extrae es la correcta y despus ejecutamos la escritura de un registro en blanco
lo que en un futuro nos indicara que el registro esta libre para ingresar nueva informacin.
#include <iostream>
#include <fstream>
using namespace std;
struct cliente{
int cuenta;
char nombre[30];
float monto;
};
int main ()
{
fstream archivo; /* crea un objeto de tipo file-stream */
/*apertura de archivo sin remplazo en modo binario de I/O */
12
Programacin 2 / C++
Eduardo Serna-Prez
archivo.open("clientes.dat", ios::binary|ios::in|ios::out);
if ( ! archivo ) { // verifica la existencia del archivo
cerr << " No se pudo abrir el archivo " << endl;
return 1; // termina el programa
}
cliente registro, blanco = {0,"",0};
int cuenta;
cout << "ingresa la cuenta a remover: ";
cin >> cuenta;
while( cuenta > 0 && cuenta <= 10){
/* localiza el registro a remover */
archivo.seekg( (cuenta -1) * sizeof(cliente) );
/* extrae los datos del registro */
archivo.read( (char*)®istro, sizeof(cliente) );
/* si el registro esta ocupado, muestra el contenido */
if ( registro.cuenta != 0) {
cout << "Nombre-> " << registro.nombre
<< " Monto-> " << registro.monto;
/* se coloca en la posicion de cuenta para escribir */
char r;
cout << "\ndeseas darlo de baja s/n ?";
cin >> r;
if (r == 's') {
archivo.seekp( (registro.cuenta -1) * sizeof(cliente) );
/* realiza la escritura del registro en blanco */
archivo.write((char *) &blanco, sizeof(cliente));
cout << "\n Datos eliminados...\n";
}
else
cout << " \nLos datos no se eliminaron\n";
}
cout << "ingresa la cuenta a remover: ";
cin >> cuenta;
}
archivo.close(); // cierra el archivo
return 0;
}
La modificacin de datos (cambios) se deja como ejercicio para los alumnos.
Bibliografa
Bjarne Stroustrup, "The C++ Programming Language", Addison-Wesley, second edition, 1991,
ISBN 0-201-53992-6.
Naba Barkakati, Object-Oriented Programming in C++, Sams, first edition, 1992, ISBN 0-67222800-9.
Harvey Deitel & Paul Deitel, Cmo programar en C++, Prentice Hall, segunda edicin, 1999,
ISBN 970-17-0254-9.
Naba Barkakati, Turbo C++ Bible, Sams, first edition, 1992, ISBN 0-672-22742-8.
13