Manejo de archivos en C++

Anuncio
Manejo de archivos en C++
1 de noviembre de 2002
1.
Streams
En C++, los archivos se manejan con un tipo particular de stream. Un stream
es una estructura de datos que se utiliza para manejar un “flujo de caracteres”
y permitir poner o sacar de él tipos de datos estándar o clases definidas por el
usuario. Por ejemplo, cout es un stream que nos permite escribir caracteres en
la consola. Repasemos un poco el funcionamiento de cout y cin:
#include <iostream>
using namespace std;
void main()
{
int n;
cout << "Ingrese un numero entero" << endl;
cin >> n;
cout << "El numero que usted ingreso es el " << n << endl;
}
En este ejemplo podemos ver los dos operadores principales que se usan para
trabajar con streams: << para streams de salida y >> para streams de entrada.
Para recordar mejor el significado de estos operadores, podemos pensar que <<
“pone” las cosas en el stream y que >> las “saca”. Además, podemos ver que
ambos operadores “saben” convertir entre enteros y caracteres, en el sentido en
que corresponda. Estos dos operadores se pueden definir para cualquier clase,
pero nosotros no vamos a trabajar con entrada y salida redefiniéndolos.
cin es un ejemplo de un istream y cout es un ejemplo de un ostream.
1.1.
>>
Este operador, también llamado “de extracción”, saca cosas de un stream
y las coloca en la variable recibida como parámetro. En su comportamiento
por defecto, este operador ignora los espacios en blanco. Para entender esto,
supongamos que el stream contiene lo siguiente:
1 2 3 4
|
1
AyEDI — 2do cuatrimestre de 2002
2
(| indica dónde se va a realizar la próxima extracción). Si la siguiente instrucción
de nuestro programa es
cin >> i;
donde i es una variable de tipo int, i va a pasar a valer 1 y el estado del stream
va a ser
2 3 4
|
Si nuevamente hacemos
cin >> i;
el programa va a saltear el espacio, va a poner el 2 en i y va a dejar el puntero
en el siguiente espacio en blanco. Es decir, al leer de un stream, por defecto, se
ignoran los espacios en blanco.
1.2.
Manipuladores
Para cambiar el comportamiento de un stream, se pueden utilizar ciertas
funciones especiales, llamadas manipuladores. Los manipuladores están definidos en el archivo iomanip. Veamos algunos de los más útiles.
1.2.1.
endl
Para marcar el final de una lı́nea en un stream de salida, podemos usar el
manipulador endl
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
cout << "Hola!" << endl;
cout << "| este palito esta justo abajor de la H" << endl;
}
1.2.2.
skipws, noskipws
Si estamos trabajando con un stream de entrada, y queremos que >> no
ignore los espacios en blanco, el manipulador noskipws es justo lo que necesitamos. Veamos un ejemplo:
#include <iostream>
#include <iomanip>
using namespace std;
void main()
AyEDI — 2do cuatrimestre de 2002
3
{
char c;
cout << "Ingrese dos digitos separados por un espacio" << endl;
cin >> c; cout << c;
cin >> c; cout << c << endl;
cout << "Ingrese dos digitos separados por un espacio" << endl;
cin >> noskipws >> c;
cin >> c; cout << c;
cin >> c; cout << c;
cin >> c; cout << c;
}
Si el usuario ingresa
1 2
1 2
Obtiene la siguiente salida
1 2
12
1 2
1 2
Para deshacer el efecto de noskipws, simplemente utilizamos skipws.
1.2.3.
boolalpha, noboolalpha
A menudo utilizamos el stream de salida por consola para conocer el valor
de las variables de nuestro programa en distintos momentos. Cuando pedimos
mostrar una variable de tipo bool, obtenemos un 0 o un 1. Si queremos algo un
poco más significativo, podemos utilizar el manipulador boolalpha.
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
cout << true << endl;
cout << boolalpha << true << endl;
}
La salida de este programa es
1
true
Nuevamente, para deshacer el efecto de boolalpha, utilizamos noboolalpha.
AyEDI — 2do cuatrimestre de 2002
2.
4
Archivos
En C++, los archivos se manejan mediante filestreams o fstreams. Estos
son streams que además proveen funciones para manipular archivos. Es decir, si
nuestro programa escribe cosas en la consola, con los mismos comandos podemos
escribir cosas en un archivo. Simplemente hay que cambiar cout por el nombre
del stream que maneje nuestro archivo.
2.1.
Entrada
Para abrir un archivo para lectura, utilizamos un ifstream. Para eso, tenemos que definir una variable de ese tipo y vincularla a algún archivo. Para
realizar esta vinculacion, tenemos dos métodos: dar el nombre del archivo al declarar la variable o utilizar el método open. Ambos producen el mismo resultado.
Veamos un ejemplo.
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
void main()
{
ifstream entrada("Hola.txt");
ifstream input;
char c;
input.open("Hello.txt");
if (entrada.good())
cout << "El archivo Hola.txt fue abierto correctamente";
else
cout << "El archivo Hola.txt no pudo ser abierto correctamente";
cout << endl;
entrada >> c;
entrada.close();
input.close()
cout << c << endl;
}
En este ejemplo, nuestro programa abre dos archivos para entrada y lee un
caracter de uno de ellos. Cuando los archivos ya no son necesarios, los cerramos
utilizando el método close. Una vez que cerramos el archivo, podemos usar el
mismo ifstream para leer de otro archivo distinto, o del mismo archivo una vez
más.
Además de la apertura de archivos de entrada, vemos el uso del método
good. Este método está presente en todos los streams y nos indica si la próxima
AyEDI — 2do cuatrimestre de 2002
5
operación de lectura/escritura será viable. En el caso de archivos, preguntar
good después de abrir un archivo nos informa si se pudo abrir correctamente.
Cuando se trabaja con streams de entrada, a menudo es necesario leer un
caracter y volverlo a poner dentro del stream. Para eso, los istreams poseen el
método putback(char), que coloca el caracter en el stream, pasando a ser el
próximo caracter que se leerá.
Otro método útil para manipular ifstreams es eof(). Este nos dice si ya
llegamos al final del archivo. Eso quiere decir que ya no se podrá leer más.
2.2.
Salida
Para manejar un archivo de salida, utilizamos un ostream
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
void main()
{
ofstream salida("Hola.txt");
ofstream output;
char c;
output.open("Hello.txt");
cin >> c;
salida << c;
salida.close();
output.close();
}
En este ejemplo, no revisamos si el archivo fue abierto correctamente. Si el
archivo no existe, se creará. Solo puede haber problemas si no se puede crear
un archivo con ese nombre en el directorio o si alguien tiene el archivo abierto.
C++ permite abrir un archivo para escribir y leer de él, pero no utilizaremos
este tipo de fstream en la materia.
3.
Enum
enum es un mecanismo del lenguaje para definir constantes simbólicas. Por
ejemplo, si queremos representar los palos de una baraja francesa en C++, crear
una clase puede ser demasiado, ya que solo tenemos que tratar con cuatro valores
sencillos. Entonces, recurrimos al enum.
#include <iostream>
#include <iomanip>
AyEDI — 2do cuatrimestre de 2002
6
using namespace std;
enum Palo {Corazones = ’C’, Treboles = ’T’,
Diamantes = ’D’, Piques = ’P’};
void main()
{
Palo p;
p = Corazones;
cout << p << endl;
cout << char(p);
}
En este ejemplo, asignamos a cada una de las constantes simbólicas (Corazones,
etc.) un caracter. Ese caracter podrı́a usarse, por ejemplo, para almacenar el palo
en un archivo.
La salida de este ejemplo es
67
C
Esto nos muestra que C++ trata a los enum como enteros. Si queremos ver (o
guarda en un archivo) el caracter correspondiente al palo, debemos encerrar la
variable en un char().
Una forma alternativa de leer y escribir enums en streams es usar los métodos
put y get. Estos solo manejan un caracter. Entonces, si queremos escribir en
patalla un Trebol, podemos hacer
cout.put(Trebol);
cout << endl;
Esto nos dará
T
Leer un enumerado es más complicado. Debemos poner el contenido en un char
y después asignarlo al enumerado. Si el usuario ingresa P
char c;
Palo p;
cin >> c;
p = Palo(c);
dejará en p el valor Piques.
4.
DJGPP
El compilador que la cátedra utiliza no cumple en un 100 % con el estándar
ANSI C++. En particular, no posee manipuladores (a excepción de endl y
AyEDI — 2do cuatrimestre de 2002
7
algún otro no muy relevante). De todas formas, sı́ brinda una forma de cambiar
el comportamiento de un istream respecto a los espacios en blanco. Para hacer
que éstos no sean ignorados, debemos usar el método unsetf de la siguiente
forma
cin.unsetf(ios::skipws);
Si queremos volver a ignorar los espacios en blanco, hacemos
cin.setf(ios::skipws);
Descargar