Vous êtes sur la page 1sur 26

9 GESTIN BSICA

DE
FICHEROS

Contenido
___________________________________________________________________________

9.1.- Introduccin .
9.2.- Archivos C++.
9.2.1.- Apertura de ficheros.
9.2.2.- Cierre de ficheros.
9.2.3.- Deteccin de fin de fichero y otras funciones.
9.2.4.- Comprobacin de apertura correcta.
9.3.- Lectura/Escritura en ficheros de texto.
9.3.1.- Avance del cursor.
9.3.2.- Ficheros de texto.
9.4.- Ficheros binarios.
9.4.1.- Utilidad de los ficheros binarios.
9.4.2.- Lectura/Escritura byte a byte.
9.4.3.- Lectura/Escritura por bloques de bytes.
9.5.- Acceso aleatorio a ficheros.
9.6.- Ficheros pasados como argumentos.
9.7.- Ejemplos de utilizacin de ficheros binarios y de texto.

Ejercicios.
___________________________________________________________________________
En este captulo vamos a tratar la gestin bsica de ficheros (tambin llamados archivos) en C++
y lo haremos a partir del concepto de flujo.

Vamos a estudiar cmo declarar los identificadores que establecen el modo de flujos de los
ficheros (de entrada o salida bsicamente) y procuraremos no entrar en el concepto de clase de
manera que la gestin de ficheros resulte asimilable por el alumno con los conceptos aprendidos
hasta el momento.

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 1
9.1.- INTRODUCCION.

En este tema se vern las caractersticas bsicas que nos permitirn trabajar con ficheros
(tambin llamados archivos).

Por qu se necesitan los ficheros?

Todos los programas vistos hasta ahora trabajaban con informacin almacenada en
memoria principal, no obstante, hay situaciones en que esto no es apropiado. Algunas de esas
situaciones podran ser:

* Los datos con los que necesita trabajar el programa son demasiado grandes (ocupan
mucha memoria) para que entren en la memoria principal.

* Nos interesa mantener la informacin despus de cada ejecucin, necesitamos


utilizar datos procedentes de otros programas (editores, etc.), o generar datos para
que puedan ser utilizados por otros programas.

En dichos casos se utilizarn ficheros para contener la informacin en memoria


secundaria (disco duro, disquetes, etc.).

Definicin de Fichero:

Es una coleccin de elementos lgicamente relacionados y almacenados en memoria


secundaria. A ms bajo nivel, un fichero es una secuencia de bits almacenado en algn
dispositivo externo (como por ejemplo uno de memoria secundaria).

9.2.- ARCHIVOS EN C++.

En los temas anteriores hemos visto que los datos de entrada o salida en un programa
C++ son obtenidos o enviados directamente a travs de lo que llamamos flujos de entrada o
salida. Hasta hora hemos manejado los flujos estndares cin y cout, y una serie de operadores
(<< y >>) y funciones (como get o getline por ejemplo) disponibles a partir de la biblioteca
iostream y que son tiles para la entrada/salida de la informacin.

En C++ un fichero es simplemente un flujo externo que se puede abrir para entrada
(dando lugar a un flujo de archivo de entrada que, para simplificar, llamaremos simplemente
archivo o fichero de entrada), para salida (dando lugar a un flujo de archivo de salida que,
para simplificar, llamaremos simplemente archivo o fichero de salida) o para entrada-salida
(archivo o fichero de entrada-salida o archivo de E/S).

C++ soporta dos tipos de archivos: de texto y binarios. Los primeros almacenan datos
como cdigos ASCII. Los valores simples, tales como nmeros y caracteres estn separados

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 2
por espacios. Los segundos almacenan bits de forma directa y se necesita usar la direccin de
una posicin de almacenamiento.

Una biblioteca en C++ que proporciona funciones y operadores para el manejo de


ficheros es la biblioteca fstream. En general emplearemos sta para la gestin bsica de
ficheros por lo que deberemos incluir el archivo de cabecera correspondiente en nuestros
programas mediante la declaracin adecuada, o sea, incluyendo la directiva de pre-
procesamiento siguiente

#include <fstream.h>

La biblioteca fstream ofrece un conjunto de funciones y operadores comunes a todas las


operaciones de Entrada/Salida (E/S) de ficheros.

9.2.1.- Apertura de ficheros.

Antes de que un programa pueda manipular un fichero para leer o escribir informacin se
debe abrir (o crear si es necesario) el fichero para identificar la posicin del mismo en el
programa (o sea, la direccin de memoria a partir de la cual almacenaremos o leeremos el
contenido del fichero). Ya hemos indicado anteriormente que los archivos son tratados como
flujos de entrada/salida por lo que, al igual que sucede con los flujos estndares y por defecto
cin y cout, la informacin debe ser transferida en una sola direccin por lo que, salvo en
ciertos casos, los ficheros deben abrirse bien para entrada o bien para salida.

9.2.1.1.- Ficheros de entrada o salida.

Supongamos que tenemos un fichero cuyo nombre en el sistema operativo es


nombre.extensin. Entonces hay varias formas de abrirlo.

(A) Como fichero de entrada: Para ello empleamos la siguiente declaracin

ifstream descriptor (nombre.extensin);

(B) Como fichero de salida: Para ello empleamos la sentencia

ofstream descriptor (nombre.extensin);

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 3
En ambos casos descriptor es una variable que se asocia al fichero cuyo nombre es
nombre.extensin.

Comentario:
Observe que a partir de la apertura de un fichero, el descriptor del fichero ser utilizado en
todas las operaciones que se realicen sobre el fichero (OJO! no utilizamos el nombre
original del fichero).

Otra forma de abrir un fichero para operar sobre l consiste en crear primero el flujo de
entrada asociado al mismo, o sea, en asociar una variable descriptor a un fichero en una
forma similar a como se declara una variable en C++, es decir, mediante una sentencia tal
como

ifstream descriptor; // Para ficheros de entrada

ofstream descriptor; // Para ficheros de salida

y, posteriormente, abrir el fichero (en el modo deseado: de entrada o salida por ejemplo)
mediante el uso de la funcin open aplicada a ese flujo de entrada, o sea en la forma

descriptor.open(nombre.extensin,int modo);

donde la variable modo indica el modo de apertura del fichero y los modos de apertura,
posiblemente combinados mediante el smbolo | como veremos a continuacin, pueden ser:

ios:: in // Modo entrada


ios:: out // Modo salida
ios:: app // Modo aadir, o sea, posicionar el cursor del fichero (ver abajo)
// al final del fichero antes de cada escritura
ios:: binary // El archivo se abre en modo binario
ios:: nocreate // Genera un error si el fichero no existe
ios:: noreplace // Genera un error si el fichero existe ya

Un archivo abierto con ofstream puede serlo en dos modos:

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 4
1. Modo salida, usando ios::out. En este caso todos los datos en el fichero se
descartan (o sea, se borra el contenido del fichero si existe previamente).
Naturalmente si el fichero no existe lo crea. En ambos casos el cursor del fichero (o
sea, la cabeza de lectura/escritura del mismo) se posiciona al principio del fichero.
Este es el modo por defecto de apertura de un fichero de salida.
2. Modo aadir, usando ios::app. En este caso los datos adicionales se aaden a
partir del final del fichero (o sea, el cursor se sita al final del fichero y es ah a
partir de donde se empieza a realizar la escritura).

Tambin se pueden combinar las dos formas anteriormente vistas de forma que el descriptor
de fichero es declarado a la vez que el fichero es abierto. Para ello empleamos las siguientes
declaraciones (segn el fichero se abra para entrada o para salida):

ifstream descriptor(nombre.extensin,int modo); // para entrada

ofstream descriptor(nombre.extensin,int modo); // para salida

donde modo es como se ha mostrado anteriormente.

Ejemplo 1:

Las dos lneas siguientes abren el fichero mio.txt como fichero de entrada (para lectura) y
lo asocian al descriptor in.

ifstream in; // descriptor del fichero a abrir


in.open(mio.txt); // Apertura del fichero;

Esas dos lneas equivalen a la siguiente:

ifstream in (mio.txt); // Apertura del fichero;

Ejemplo 2:

Para abrir el fichero salida.dat en modo salida (si el fichero no existe lo crea, y si existe
borra su contenido) asocindolo al descriptor out podemos usar la siguiente sentencia;

ofstream out("salida.dat");

o la siguiente

ofstream out("salida.dat", ios::out);

o tambin

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 5
ofstream out;
out.open("salida.dat");

9.2.1.2.- Ficheros de entrada/ salida.

Un fichero puede ser tambin abierto para entrada-salida. En este caso emplearemos una
declaracin fstream combinada con la operacin de apertura correspondiente, o sea:

fstream descriptor;
descriptor.open(nombrefichero.ext, ios::in | ios::out)

O alternativamente podemos combinar la declaracin y la apertura en una sola sentencia. Por


ejemplo:

fstream descriptor(nombre.extensin,ios::in | ios:: out); // para entrada-salida

La declaracin fstream puede ser usada arbitrariamente tanto sobre archivos de escritura
como sobre archivos de lectura, aunque recomendamos que para archivos de solo-lectura se
use ifstream y para aquellos de solo-escritura se use ofstream.

Comentario:
Cuando un fichero de E/S se declara con fstream, abrirlo con open debemos especificar el
modo de apertura que queremos (entrada, salida o bien entrada.salida).

Ejemplo 3:

// Abrimos el fichero F1.dat como fichero de entrada


fstream inout;
inout.open("F1.dat", ios::in);

// Intentamos abrir el fichero F1.dat pero tenemos un error puesto que no


// hemos especificado el modo de apertura
fstream inout;
inout.open("F1.dat");

// Abrimos el fichero F2.txt como fichero de salida en modo AADIR.


fstream inout;
inout.open("F2.txt", ios::app);

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 6
// Abrimos el fichero binario.dat para entrada-salida binaria y le asociamos el
// descriptor ejemplo.
fstream ejemplo ("binario.dat", ios::in | ios:: out | ios::binary);

9.2.2.- Cierre de ficheros.

Un fichero anteriormente abierto y con un descriptor asociado a l debe ser cerrado con
el fin de liberar los recursos asociado a l de la siguiente forma:

descriptor.close()

9.2.3.- Deteccin de fin de fichero y otras funciones.

Adems de las funciones open y close, existen otras funciones disponibles en la


biblioteca fstream, que pueden ser aplicadas directamente al descriptor de un fichero en la
forma

Descriptor.funcin();

Donde funcin es una de las siguientes:

La funcin eof() que devuelve "true" si se ha alcanzado el final del fichero y falso
en cualquier otro caso.

LECTURA ADELANTADA: Para que la funcin eof() devuelva un valor de


verdad (actualizado) es necesario, en muchos casos, realizar una operacin de
lectura previa. Esto permite que se actualice el valor a devolver por la funcin eof
comprobndose si tras realizar dicha operacin se ha llegado al final del fichero.
A este proceso lo llamaremos lectura adelantada (ver el ejemplo 6).

La funciones fail() o bad() que devuelven "true" si existe un error en una


operacin de flujo asociada al fichero identificado por la variable descriptor
(bien sea en una apertura, un cierre, una escritura o una lectura entre otras
posibles operaciones) y "false" en caso contrario. La diferencia entre estas dos

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 7
funciones es muy sutil. En realidad un flujo puede estar en un estado de fallo (i.e.,
fail) pero no en un estado errneo (i.e. bad) en el caso de que el flujo no se
considere corrupto ya que no se han perdido los caracteres que provienen del
flujo (en un estado errneo, esto puede no ocurrir). Recomendamos un vistazo a
algn manual de C++ para aclarar las diferencias tan sutiles.

La funcin good() que devuelve "true" si no existe un error en una operacin de


flujo y "false" en caso contrario.

9.2.4.- Comprobacin de apertura correcta

Antes de empezar a leer o escribir en un fichero es siempre conveniente verificar que la


operacin de apertura se realiz con xito. La comprobacin del "buen estado" de un
determinado flujo asociado a un fichero se puede realizar preguntando directamente sobre el
descriptor de fichero asociado (al igual que se hace con los flujos estndares cin y cout) en la
forma siguiente:

if (descriptor) if (! descriptor)
{ {
//Buen estado. Continuamos // Mal estado. Escribimos un mensaje
// operando sobre el fichero // a la salida estndar
..... cout << Error en la apertura
} .....
}

o mejor aun, utilizando las funciones good y bad (o fail) vistas anteriormente, o sea:

if (descriptor.good()) if (descriptor.bad()) // o descriptor.fail()


{ { // Mal estado. Escribimos un mensaje
//Buen estado. Continuamos // a la salida estndar
// operando sobre el fichero cout << Error en la apertura
..... }
}

Ejemplo 4:
ifstream in("F1.dat");
if (!in) // O bien, if (in.bad() )
{
cout << endl <<"Incapaz de crear o abrir el fichero " << endl;

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 8
// salida estndar
cout << " para entrada " << endl;
}
else
{
. // Se opera sobre el fichero
}

9.3.- LECTURA-ESCRITURA EN FICHEROS (DE TEXTO).

9.3.1.- Avance del cursor

Tanto para los ficheros de texto como para los ficheros binarios existe lo que se
denomina el cursor o apuntador del fichero que es un ndice que direcciona una posicin
relativa del fichero. El cursor marca en todo momento la posicin actual del fichero a partir
de la cual va a tener lugar la siguiente operacin de entrada-salida a ejecutar sobre el mismo
(bien sea una operacin de lectura o una de escritura). Cada vez que se realiza una operacin
de entrada o salida, el cursor del fichero avanza automticamente el nmero de bytes ledos o
escritos.

9.3.2.- Ficheros de texto

La lectura y la escritura en un archivo de texto se puede realizar directamente con los


operadores << y >> al igual que se realiza sobre los flujos estndares cin y cout.

Ejemplo 5:

El siguiente programa escribe tres lneas en un fichero llamado EJEMPLO5.TXT que se


crea en el programa (si ya existe borramos su contenido). Cada lnea consta de un entero, un
real y una cadena de caracteres. Los datos en cada lnea estn separados por espacios en
blanco.

#include <fstream.h> // Biblioteca para el manejo de ficheros


#include <iostream.h> // Biblioteca para la entrada-salida estndar

int main(){
ofstream fichout("EJEMPLO5.TXT",ios::out);
if (!fichout)
{
cout << endl << "Incapaz de crear este o abrir el fichero " << endl;
}
else
{
fichout << 1 << " " << 5.0 << " APROBADO" << endl;
// Escritura en el fichero
fichout << 2 << " " << 1.1 << " SUSPENSO" << endl;
fichout << 3 << " " << 8.0 << " NOTABLE " << endl;
fichout.close();
}
} // Fin del main

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 9
Comentario:
El operador >> omite los espacios en blanco al igual que ocurra en la entrada estndar.

Ejemplo 6:

El siguiente programa lee el fichero de texto EJEMPLO5.TXT, creado en el ejemplo


anterior, y visualiza su contenido en el monitor.

#include <fstream.h> // Libreria para el manejo de ficheros


#include <iostream.h>
typedef char TCadena[30];

int main(){
int i;
float r;
TCadena cad;

ifstream fichin("EJEMPLO5.TXT"); // declaracion y apertura del fichero


if (!fichin)
{
cout << endl << "Incapaz de crear o abrir el fichero ";
}
else
{
fichin >> i; // Observe la lectura adelantada!!!
while (!fichin.eof())
{ cout << i << " "; // Lectura de valores en el fichero
fichin >> r;
cout << r << " "; // Lectura de valores en el fichero
fichin >> cad;
cout << cad << endl; // Lectura de valores en el fichero
fichin >> i;
}
fichin.close();
} // Fin del else
} // Fin del main

Comentarios:
(1) Observe en el ejemplo anterior que ha sido necesario realizar una lectura adelantada
previamente al chequeo del fin de fichero. Si no se realiza de esta forma podriamos tener
problemas.
(2) Observe tambin que no es necesario realizar una lectura para saltarse los espacios en
blanco que fueron introducidos en el fichero EJEMPLO5.TXT en el ejemplo 5. Esto es
debido a que, como ya se coment anteriormente, el operador >> omite los espacios en
blanco
(3) No olvide cerrar los ficheros!!

9.4.- FICHEROS BINARIOS.

Hasta ahora hemos trabajado con ficheros de texto, stos pueden ser vistos como una serie de
caracteres que pertenecen a un determinado cdigo de entrada/salida, en nuestro caso al

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 10
cdigo ASCII. Tambin hemos visto cmo se abre un fichero binario. En esta seccin vamos
a ver cmo podemos leer y escribir datos en binario.

9.4.1.- Utilidad de los ficheros binarios.

En esta seccin explicamos la diferencia de los ficheros binarios con los de texto y lo
hacemos a partir de un ejemplo sencillo..

Por ejemplo, si creamos un fichero con

ofstream fich("F1.dat",ios::out);
if (!fich)
{
cout << endl << "Incapaz de crear este o abrir el fichero ";
cout << " para salida " << endl;
}
else
{
fich << "HOLA ADIOS"; // Escribe la cadena en el fichero
// "F1.dat"
fich.close();
}

F1.dat ser un fichero que contiene 10 bytes, donde cada uno ser el cdigo ASCII
correspondiente a cada uno de los caracteres que hemos escrito en el fichero (un carcter
ocupa un byte). Esta caracterstica hace que un fichero de texto pueda ser usado por otros
programas que supongan que el contenido del fichero es un conjunto de caracteres del cdigo
ASCII.

Sabemos que los datos se almacenan en memoria segn las caractersticas del tipo con
que han sido declarados. As, para:

char C;
unsigned N;

La variable C usa un byte en memoria principal, y en el se almacena el cdigo ASCII de


un carcter, mientras que la variable N, al ser de tipo entero sin signo, usa dos bytes, y en
ellos se almacena el cdigo binario correspondiente a un nmero entero sin signo. Esta
caracterstica sugiere que para almacenar en el fichero de texto el nmero contenido en la

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 11
variable N no basta con grabar directamente los dos bytes en el fichero (Ejemplo, si N
contiene el nmero 13864, para almacenarlo en el fichero se requieren 5 caracteres- o sea, 5
bytes-, mientras que en memoria la variable N ocupa cuatro bytes). As pues, una instruccin

fich << N;

ocasionar dos pasos:

1) Convertir N a su configuracin en caracteres ASCII.

2) Escribir en el fichero los caracteres ASCII obtenidos.

En el caso del tipo CHAR, no es necesario efectuar la conversin pues la variable en


memoria principal se corresponde con (es decir, contendr como valor) el cdigo ASCII
correspondiente al carcter almacenado en la misma.

Hay situaciones en las que en lugar de convertir los valores a escribir en el fichero en una
serie de caracteres, puede resultar til efectuar la grabacin en el fichero directamente a partir
contenido de la memoria. A los ficheros creados de esta forma se les llama ficheros binarios.

Ventajas del uso de ficheros binarios::

El proceso de lectura escritura es ms rpido, pues nos ahorramos el tiempo


necesario para la conversin.

Normalmente un fichero binario ocupa menos memoria que su correspondiente


fichero de texto (Ejemplo, escribir 32534 en formato de texto ocupara cinco
bytes, mientras que hacerlo en formato binario ocupara dos bytes).

Inconvenientes del uso de ficheros binarios:

No podrn ser usados por programas de carcter general. Por ejemplo, si intento
usar la orden TYPE (de MS-DOS) o la orden cat (de UNIX) con un fichero
binario, la informacin que obtengo por pantalla no es legible.

De todo lo dicho anteriormente se desprende que es conveniente usar ficheros de texto


cuando pueda interesarnos tratar la informacin contenida en stos con programas de carcter
general (Editor, TYPE, PRINT, etc.), y en otro caso usar ficheros binarios.

Tratamiento de ficheros binarios.

Puesto que no hay que distinguir entre diferentes formatos para diferentes tipos de datos,
slo se necesitan instrucciones que lean y escriban un cierto nmero de bytes por lo que en
realidad slo necesitamos un tipo de instruccin para lectura y un tipo de instruccin para

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 12
escritura. An as veremos dos formas diferentes de leer y escribir desde y en ficheros
binarios.

9.4.2.- Lectura/Escritura byte a byte.

9.4.2.1.- Lectura.

Para leer un carcter (es decir un byte) desde un fichero usamos la funcin get aplicada sobre
el descriptor del mismo de la siguiente manera

descriptor.get(ch);

Esta instruccin extrae un nico carcter del flujo de entrada, incluyendo el espacio en blanco
y lo almacena en la variable ch (que debe ser declarada de tipo carcter). Esta funcin avanza
adems un byte la posicin del cursor del archivo identificado por la variable descriptor.

Ejemplo 7:

El siguiente programa lee (byte a byte) un fichero binario que contiene caracteres y visualiza
su contenido en el monitor.

#include <fstream.h> // Librera para el manejo de ficheros


#include <iostream.h>

int main()
{
char c;
ifstream fichin("F1.dat",ios::in | ios::binary);
if (!fichin)
{
cout << endl <<"Incapaz de Abrir el fichero ";
}
else
{
fichin.get(c); // LECTURA ADELANTADA!!
while (fichin) // Tambien vale 'while (!fichin.eof())'
{ cout << c;
fichin.get(c);
};
fichin.close();
} // Fin del else

} // Fin del main

9.4.2.2.- Escritura.

Para escribir o mandar un carcter (es decir un byte) a un archivo de de salida usamos la
funcin put aplicada al descriptor de fichero del archivo de la siguiente manera

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 13
descriptor.put(ch);

Esta instruccin coloca el carcter contenido en ch en el archivo de salida identificado por la


variable descriptor (o sea, en su caso en el fichero asociado a dicho descriptor) y lo hace a
partir de la posicin actual del cursor. A continuacin avanza el cursor del fichero al
siguiente byte.

Ejemplo 8:

El siguiente programa escribe un texto (byte a byte) en el fichero Ejemplo8.dat.

#include <fstream.h>
#include <iostream.h>

int main(){

char cad[17]="TEXTO A ESCRIBIR";


ofstream fichout("Ejemplo8.dat", ios::out | ios::binary);

if (!fichout)
{
cout << endl << "Incapaz de Crear o Abrir el fichero ";
}
else
{
for (int i=0;i<=16;i++)
{ fichout.put(cad[i]); // Escritura en el fichero
}
fichout.close();
} // Fin del else
} // Fin del main

9.4.3.- Lectura/Escritura por bloque de bytes.

Otra manera alternativa de leer y escribir en ficheros binarios consiste en utilizar las
funciones read() y write().

9.4.3.1.- Lectura.

La funcin read tiene varios formatos aunque a continuacin explicamos el formato


bsico

De forma intuitiva, una llamada de la forma

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 14
descriptor.read(&c, num);

donde c es una variable de un tipo arbitrario (por ejemplo de un tipo TElemento), pasada por
referencia, y num es un entero o una variable de tipo entero, ejecuta una lectura (a partir de la
posicin actual del cursor del fichero asociado a la variable descriptor) de num bytes del
fichero y los coloca en la variable c. En definitiva la llamada lee num bytes del fichero y los
coloca en la variable c. Esta funcin puede extraer caracteres hasta alcanzar el fin del fichero.

9.4.3.2.- Escritura.

Asumiendo que c es una variable de un tipo arbitrario (por ejemplo de un tipo TElemento)
pasada por referencia, que num es un entero o una variable conteniendo un entero que
descriptor esta asociado a un fichero, una llamada de la forma

Descriptor.write(&c, num);

Escribe, a partir de la posicin del cursor, el contenido de c en el fichero asociado a


descriptor. En realidad slo escribe num bytes que corresponden a los num bytes siguientes
que se encuentran en memoria a partir de la direccin en la que se encuentra almacenado el
contenido de c.

Esta instruccin escribe a partir de la posicin indicada por el puntero de lectura/escritura


del fichero asociado a descriptor los num bytes contenidos en el parmetro c.

Se puede observar que en el segundo parmetro hay que indicar el nmero de bytes que
ocupa el valor que se desea escribir. Para conocer ste dato de una forma fcil, podremos usar
la funcin sizeof.

Ejemplo 9:

El siguiente programa declara el fichero F.dat para entrada-salida, graba en dicho fichero el
valor 1234.86 en binario y despus los veinte primeros enteros. Posteriormente, lee el fichero
visualizando su informacin en la salida estndar (el monitor).

#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>

int main(){
float R=1234.86;

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 15
int i,N;

fstream fichbin("F.dat",ios::binary | ios::out); // Apertura como salida


fichbin.write(&R,sizeof(float));
for (i=1;i<=20;i++)
{ fichbin.write(&i,sizeof(int));
}

fichbin.close();

fichbin.open("F.dat",ios::binary | ios::in); // Apertura como entrada


fichbin.read(&R,sizeof(float));
cout <<endl << "R= " << R << endl;
for (i=1;i<=20;i++)
{ fichbin.read(&N,sizeof(int));
cout <<endl << i << "= " << N << endl;
}
system("PAUSE");
return 0;
} // Fin del main

Observa que la apertura y el cierre de ficheros binarios se puede efectuar con las mismas
operaciones estudiadas para ficheros de texto.

9.5. Acceso aleatorio a ficheros.

Sabemos que las operaciones de lectura y escritura siempre se realizan a partir de la


posicin indicada por el puntero de lectura/escritura del fichero. Para poder acceder
correctamente al fichero, debemos saber como cambia dicho puntero de lectura/escritura.
Hasta ahora hemos visto, que tena un comportamiento secuencial, es decir, siempre se
incrementa en el nmero de caracteres ledos escritos con cada instruccin, no obstante,
puede haber situaciones en las que ste comportamiento no se adapte a nuestras necesidades.

Supongamos que deseamos acceder a informacin situada cerca del final del fichero.
Segn lo visto hasta ahora, debemos leer previamente toda la informacin que le precede con
objeto de ir avanzando el puntero de lectura/escritura progresivamente. Puesto que
conocemos la situacin de la informacin que queremos leer escribir, parece ms
conveniente poder situar el puntero de lectura/escritura directamente en dicha posicin. Para
gestionar ste tipo de comportamiento disponemos de una serie de funciones.

Ya hemos visto que el acceso a un fichero se describe en trminos de lo que


denominamos el cursor o apuntador del fichero que es un ndice que apunta a una posicin
relativa del fichero de manera que en todo momento la posicin actual del cursor marca el
lugar a partir del cual tendr lugar la operacin (de lectura o escritura) sobre el fichero.
Adems, cada vez que se realiza una operacin de entrada o salida, el cursor del fichero
avanza automticamente dependiendo del nmero de bytes ledos o escritos. Bsicamente
existen dos instrucciones de acceso aleatorio para cada tipo de acceso a un fichero. Las

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 16
vemos a continuacin.

9.5.1.- Lectura.
Las funciones de acceso aleatorio para lectura son seekg y tellg.

seekg(pos) mueve la posicin del cursor del fichero a la posicin relativa del fichero
indicada por pos, donde pos es un entero (o variable conteniendo un entero).
tellg() devuelve la posicin relativa actual del cursor asociado al fichero de entrada y
devuelve un 1 en caso de existir algn error.

9.5.2.- Escritura.
Las funciones de acceso aleatorio equivalentes para escritura on seekp y tellp.

seekp(pos) mueve la posicin del cursor del fichero a la posicin absoluta del fichero
indicada por pos.
tellp() devuelve la posicin absoluta actual del cursor asociado al fichero de salida y
devuelve un 1 en caso de existir algn error.

Ejemplo 10:

El siguiente programa almacena en un fichero los 10 primeros enteros, luego muestra por
pantalla el quinto entero (o sea el 5), posteriormente lo reemplaza por el valor 100, y al final
visualiza en el monitor el contenido del fichero.

#include <fstream.h>
#include <iostream.h>
#include <stdlib.h>

int main(){
int i,N;

fstream fichbin("ejemplo11.dat",ios::binary | ios::in | ios::out);


for (i=1;i<=10;i++)
{ fichbin.write(&i,sizeof(int));
} // Almacena los 10 primeros enteros

fichbin.seekp(4*sizeof(int));
// se posiciona al principio del quinto entero

fichbin.read(&N,sizeof(int)); // Lee dicho entero


cout <<endl << "Quinto= " << N << endl; // visualiza el valor 5

fichbin.seekp(4*sizeof(int));
// se posiciona de nuevo al principio del quinto entero
// pues el cursor haba avanzado.
i=100;
fichbin.write(&i,sizeof(int));
// Modifica el valor 5 por el valor 100;

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 17
fichbin.seekp(0*sizeof(int));
// se posiciona de nuevo al principio del fichero
for (i=1;i<=10;i++)
{ fichbin.read(&N,sizeof(int));
cout <<endl << i << "= " << N << endl;
// Se visualiza el contenido en pantalla
}
fichbin.close();
system("PAUSE");
return 0;
} // Fin del main

9.6.- Ficheros pasados como argumentos.

En esta seccin simplemente comentamos que cuando el descriptor de un fichero es


pasado como argumento, la mayora de las veces debe hacerlo como parmetro por referencia
puesto que cualquier operacin de lectura/escritura (y la mayora de las de acceso directo)
modifican la posicin del cursor asociado a ese fichero.

Ejemplo 11:

El siguiente programa simplemente aade la cadena "HOLA" al fichero "poesia.txt". Observe


que el argumento formal del procedimiento escribir_hola esta declarado por referencia.

#include <fstream.h>

void escribir_hola(fstream &canal_salida){


canal_salida << endl << "HOLA" << endl;
}

int main(){
fstream out("poesia.txt",ios::app);
escribir_hola(out);
out.close();
} // Fin del main

9.7.- Ejemplos de utilizacin de ficheros binarios y de texto.

En esta seccin mostramos dos ejemplos de cmo podemos leer/escribir datos desde/a
ficheros binarios o de texto.

Comentario:
Observe que en la apertura de ficheros binarios ES NECESARIO, en algunos compiladores
como es el caso del DEV-C++) especificar el modo de apertura (in, out, app, ...,etc) a pesar
de que este sea el modo por defecto. Si no se especifica entonces podemos tener problemas
en la lectura de los datos.

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 18
Ejemplo 12:

El siguiente programa lee, desde teclado una informacin relativa a una serie de empleados
de una empresa. Los datos a leer son el nombre, un cdigo formado por cuatro enteros - ojo,
no por cuatro dgitos- y una cantidad correspondiente al sueldo mensual. Entonces, toda la
informacin recogida es grabada en dos ficheros (uno de texto y otro binario) para ser
posteriormente leda desde los mismos y visualizada en pantalla.

#include <iostream.h>
#include <stdlib.h>
#include <fstream.h>

//CONSTANTES
const int MAXCAD = 40;
const int MAXVECT = 4;
const char ENTER = '\n';

//TIPOS
typedef int TVector[MAXVECT];
typedef char TCadena[MAXCAD+1];
struct TPersona{
TCadena nombre;
TVector codigo; // exactamente cuatro cifras
float sueldo;
};
void VisualizaPersonasFichero(TCadena nombreFichero,int numempleados);
void EscribePersonaFichero(TCadena nombreFichero, TPersona p);
void VisualizaPersonasFicheroBin(TCadena nombreFichero,int numempleados);
void EscribePersonaFicheroBin(TCadena nombreFichero, TPersona p);
void pintaVector(TVector v);
void pintaPersona(TPersona p);
void leePersona(TPersona &p);

int main(){
TPersona per;
TVector cod;
int i,N;

cout << "introduzca el nmero de personas a incluir ";


cin >> N;
for (i=1; i <= N ; i ++)
{ leePersona(per);
// Escribo la informacin en texto y en binario
EscribePersonaFichero("empleados.txt",per);
EscribePersonaFicheroBin("empleados.dat",per);
}

cout << "Mostramos la informacin almacenada" << endl;


cout << "Visualizo desde el fichero de texto: " << endl;
VisualizaPersonasFichero("empleados.txt",N);
cout << endl;

cout << "Visualizo desde el fichero binario: " << endl;


VisualizaPersonasFicheroBin("empleados.dat",N);
cout << endl;

system("PAUSE");
return 0;
} // Fin del main

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 19
// Este proc. visualiza la informacin almacenada en el fichero de texto
void VisualizaPersonasFichero(TCadena nombreFichero, int numempleados)
{ ifstream in;
int i,j;
TPersona p;

in.open(nombreFichero);
if (in.bad()) // Comprobamos el estado de la apertura
{
cout << "Error al abrir el fichero: " << nombreFichero << endl;
}
else
{
for (i=1;i<=numempleados; i++)
{ in.getline(p.nombre,MAXCAD+1,ENTER); //USO DE getline en el fichero
for (j=0;j<MAXVECT;j++)
{ in >> p.codigo[j];
}

in >> p.sueldo;
pintaPersona(p);
in.ignore(); // Uso de ignore() sobre el descriptor
}
in.close();
}
} // Fin VisualizaPersonasFichero

// El siguiente proc. Escribe la informacion de una persona en un fichero


de texto
void EscribePersonaFichero(Tcadena nombreFichero, TPersona p)
{ ofstream out;
int i;

out.open(nombreFichero,ios::app);
if (out.bad())
{
cout << "Error al abrir el fichero: " << nombreFichero << endl;
}
else
{
out << p.nombre << endl;

for(i=0;i<MAXVECT;++i)
{ out << p.codigo[i] << ' '; // Ojo, incluimos un espacio en medio!!
}

out << p.sueldo << endl;


out.close();
}
} // Fin EscribePersonaFichero

// Este proc. visualiza la informacin almacenada en el fichero binario


void VisualizaPersonasFicheroBin(TCadena nombreFichero,int numempleados)
{ ifstream in;
int i;
Tpersona p;

in.open(nombreFichero, ios::in | ios::binary);


// Ojo, hay que poner 'in' forzosamente

if (in.bad())
{

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 20
cout << "Error al abrir el fichero: " << nombreFichero << endl;
}
else
{
for (i=1;i<=numempleados;i++)
{
in.read(&p,sizeof(TPersona)); // Se lee toda la informacin !!
pintaPersona(p);
}
in.close();
}
} // Fin VisualizaPersonasFicheros

// El siguiente proc. Escribe la informacion de una persona en un fichero


binario
void EscribePersonaFicheroBin(TCadena nombreFichero, TPersona p)
{ ofstream out;

out.open(nombreFichero, ios::binary | ios::app);


// Ojo, especificamos el modo AADIR

if (out.bad())
{
cout << "Error al abrir el fichero: " << nombreFichero << endl;
}
else
{
out.write(&p,sizeof(TPersona));
out.close();
}
} // Fin EscribePersonaFicheroBin

// El siguiente proc. visualiza un cdigo de cuatro enteros (o sea, un


vector) a la pantalla
void pintaVector(TVector v){
int i;
cout << "CODIGO : { ";
for(i=0;i<MAXVECT-1;++i)
{ cout << v[i] << ", " ;
}
cout << v[MAXVECT-1] << " } " << endl;
}

// El siguiente proc. Visualiza la informacin de una persona en la


pantalla
void pintaPersona(Tpersona p){
cout << "NOMBRE : " << p.nombre << " ";
pintaVector(p.codigo);
cout << "SUELDO : " << p.sueldo << endl;
}

// El siguiente proc, lee informacin de una persona desde el teclado


void leePersona(TPersona &p)
{
int i;
cin.ignore(); // Para limpiar el buffer de teclado
cout << "Nombre ? ";
cin.getline(p.nombre,MAXCAD+1,ENTER);

cout << endl << "Codigo (4 enteros-NO cifras solo) ?";


for(i=0;i<MAXVECT;++i)
{ cin >> p.codigo[i];
}

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 21
cout << endl << "Sueldo (euros) ?";
cin >> p.sueldo;
}

Comentarios:

1. El primer argumento de read y write no necesita el smbolo & cuando es de tipo


array como se ve en el siguiente ejemplo.

2. Observe que es posible usar ignore() y getline() sobre el descriptor de un


fichero y que funcionan de manera anloga a su aplicacin sobre cin.

Ejemplo 13:
El siguiente programa escribe el vector que contiene la informacin {0,1,2,3,....,8,9} tanto en
un fichero binario como en uno de texto.

#include <iostream.h>
#include <stdlib.h>
#include <fstream.h>

//CONSTANTES
const int MAXCAD = 20;
const int MAXVECT = 10;

//TIPOS
typedef int TVector[MAXVECT];
typedef char TCadena[MAXCAD+1];

void LeeVectorFichero(TCadena nombreFichero, TVector &v);


void EscribeVectorFichero(TCadena nombreFichero, TVector v);
void LeeVectorFicheroBin(TCadena nombreFichero, TVector &v);
void EscribeVectorFicheroBin(TCadena nombreFichero, TVector v);
void pintaVector(TVector v);

int main()
{ TVector v;
int i;

for(i=0;i<MAXVECT;++i) // Inicializo el vector


{ v[i]=i;
}
cout << "Inicializo el vector y lo escribo "
<< "en ficheros de texto y binario: "
<< endl;
pintaVector(v);
EscribeVectorFichero("vector.txt",v);
EscribeVectorFicheroBin("vector.dat",v);

for(i=0;i<MAXVECT;++i) // Borro el vector


{ v[i]=0;
}
cout << "Reseteo el contenido del vector:"
<< endl;
pintaVector(v);

cout << "Leo v desde el fichero de texto: " << endl;

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 22
LeeVectorFichero("vector.txt",v);
pintaVector(v);

cout << "Leo v desde el fichero binario: " << endl;


LeeVectorFicheroBin("vector.dat",v);
pintaVector(v);

system("PAUSE");
return 0;
}

// Lee un vector desde un fichero de texto


void LeeVectorFichero(TCadena nombreFichero, TVector &v)
{ ifstream in;
int i;

in.open(nombreFichero);
if (in.bad()) // Comprobamos el estado de la apertura
{ cout << "Error al abrir el fichero: "
<< nombreFichero << endl;
}
else
{ for(i=0;i<MAXVECT;++i)
{ in >> v[i];
}

in.close();
}
}

// Escribe un vector en un fichero de texto


void EscribeVectorFichero(TCadena nombreFichero, TVector v)
{ ofstream out;
int i;

out.open(nombreFichero);

if (out.bad())
{ cout << "Error al abrir el fichero: "
<< nombreFichero << endl;
}
else
{ for(i=0;i<MAXVECT;++i)
{ out << v[i] << " ";
}

out.close();
}
}

// Lee un vector desde un fichero binario


void LeeVectorFicheroBin(TCadena nombreFichero, TVector &v)
{ ifstream in;

in.open(nombreFichero);

if (in.bad())
{ cout << "Error al abrir el fichero: "
<< nombreFichero << endl;
}
else
{ in.read(v,sizeof(TVector));
in.close();
}
}

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 23
// Escribe un vector a un fichero binario
void EscribeVectorFicheroBin(TCadena nombreFichero, TVector v)
{ ofstream out;

out.open(nombreFichero);

if (out.bad())
{ cout << "Error al abrir el fichero: "
<< nombreFichero << endl;
}
else
{ out.write(v,sizeof(TVector));
out.close();
}
}

// Visualiza un vector a la pantalla


void pintaVector(TVector v)
{ int i;

cout << " v = { ";


for(i=0;i<MAXVECT-1;++i)
{ cout << v[i] << ", " ;
}
cout << v[MAXVECT-1] << " } " << endl;

Una vez ejecutado el programa la salida es la siguiente:

Inicializo el vector y lo escribo en ficheros de texto y binario:


v ={0,1,2,3,4,5,6,7,8,9}
Reseteo el contenido del vector
v={0,0,0,0,0,0,0,0,0,0}
Leo v desde el fichero de texto
v ={0,1,2,3,4,5,6,7,8,9}
Leo v desde el fichero binario
v ={0,1,2,3,4,5,6,7,8,9}
Presione cualquier tecla para continuar...........

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 24
EJERCICIOS

1.- Escribir un programa con la opcin de encriptar y de desencriptar un fichero de texto.


La encriptacin (codificacin) consiste en que dado un fichero de texto de entrada genere otro
fichero de salida de extensin <nombre>.COD donde el texto estar codificado (encriptado).
Esta codificacin consiste en reemplazar cada carcter por el tercero siguiente (ej. a -> d). Si
el carcter resultante es no imprimible ste no se cambia. La opcin de desencriptado consiste
en leer un fichero <nombre>.COD y recuperar la informacin original.

2.- Escriba un programa que cree un fichero de texto llamado "PERSONAS.DAT" en el


que se guarde la informacin de un nmero indeterminado de personas. La informacin que
se guardar por cada persona ser:

Nombre: De 1 a 30 caracteres.
Edad CARDINAL.
Sexo CHAR (M/F).
Arte CHAR (S/N).
Deporte CHAR (S/N).
Libros CHAR (S/N).
MsicaCHAR (S/N).

La informacin correspondiente a cada persona se leer del teclado. El proceso


finalizar cuando se teclee un campo "Nombre" que est vaco.

3.- Ample el programa que procesa clientes de una agencia matrimonial para que tome
los datos de todos los candidatos a estudiar del fichero PERSONAS.DAT del ejercicio
anterior, lea el cliente del teclado y finalmente genere como resultado un listado por pantalla
con los nombres de los candidatos aceptados y un fichero llamado ACEPTADOS.DAT con
toda la informacin correspondiente a los candidatos aceptados. Una persona del fichero
PERSONAS.DAT se considerar aceptable como candidato si tiene diferente sexo y por lo
menos tres aficiones comunes con respecto al aspirante introducido por pantalla. (El
programa debe ser capaz de trabajar con cualquier nmero de personas en el fichero
PERSONAS.DAT).

4.- Codifique un programa que cree un fichero para contener los datos relativos a los
artculos de un almacn. Para cada artculo habr de guardar la siguiente informacin:

Cdigo del artculo (Numrico)


Nombre del artculo (Cadena de caracteres)
Existencias actuales (Numrico)
Precio (Numrico).
Se debern pedir datos de cada artculo por teclado hasta que como cdigo se teclee 0.
El fichero se habr de crear ordenado por el cdigo del articulo.

5.- Escriba un programa que dados dos ficheros generados por el programa anterior y
ordenados genere un tercer fichero que sea el resultado de mezclar de formar ordenada los
dos primeros.

6.- Escriba un programa que tome como entrada el fichero del ejercicio 4 y una condicin
sobre los campos Existencias actuales o Precio. La condicin podr ser:

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 25
<campo> [<,<=,>,>=, != ] <nmero>

Este programa debe generar como salida un fichero llamado "salida.dat" que contenga todos
aquellos artculos para los que se cumple la condicin de entrada.

7.- Escriba un programa que tenga como entrada un fichero que contenga un texto y d
como resultado una estadstica de las palabras que hay de cada longitud, as como de los
caracteres especiales (",", ".", ":", ";").

8.- Escribir un programa que genere a partir de un fichero de entrada que contiene una
tabla de nmeros reales otro fichero de salida <nombre>.BIN grabado en formato binario.

Ej: 1.23 3.45 12.5


4.8 3.9 0.83
........................
9.- Dado una tabla grabada en un fichero en formato binario <nombre>.BIN hallar la
suma horizontal y vertical y grabar la tabla y los resultados en otro fichero de texto o binario
segn se introduzca por pantalla. El resultado en texto sera el siguiente:
Ej: 1.23 3.45 12.5 17,18
4.8 3.9 0.83 9,53
6,03 7,35 13,33

___________________________________________________________________________
Laboratorio de Programacin GESTION BASICA DE FICHEROS Pg 26

Vous aimerez peut-être aussi