En C, el proceso de abrir y manipular ficheros requería un gran
conocimiento del lenguaje para prepararle para la complejidad de
las operaciones. Sin embargo, la librería
iostream
de C++ proporciona una forma
simple de manejar ficheros, y por eso se puede presentar mucho
antes de lo que se haría en C.
Para poder abrir un fichero para leer y escribir, debe incluir la
librería fstream
. Aunque eso implica la
inclusión automática de la librería
iostream
, es prudente incluir
iostream
si planea usar
cin
, cout
, etc.
Para abrir un fichero para lectura, debe crear un objeto
ifstream
que se usará como
cin
. Para crear un fichero de escritura, se
crea un objeto ofstream
que se comporta
como cout
. Una vez que tiene abierto el fichero
puede leer o escribir en él como si usara cualquier objeto
iostream
. Así de simple, que es el objetivo, por
supuesto.
Una de funciones las más útiles de la librería
iostream
es getline()
,
que permite leer una línea (terminada en nueva línea) y guardarla
en un objeto string
[37]. El primer argumento es el objeto
ifstream
del que se va a leer la
información y el segundo argumento es el objeto
string
. Cuando termina la llamada a la
función, el objeto string
contiene la
línea capturada.
Aquí hay un ejemplo que copia el contenido de un fichero en otro.
//: C02:Scopy.cpp // Copy one file to another, a line at a time #include <string> #include <fstream> using namespace std; int main() { ifstream in("Scopy.cpp"); // Open for reading ofstream out("Scopy2.cpp"); // Open for writing string s; while(getline(in, s)) // Discards newline char out << s << "\n"; // ... must add it back } ///:~
Listado 2.8. C02/Scopy.cpp
Para abrir los ficheros, únicamente debe controlar los
nombres de fichero que se usan en la creación de los objetos
ifstream
y
ofstream
.
Aquí se presenta un nuevo concepto: el bucle
while
. Aunque será explicado en detalle en el siguiente
capítulo, la idea básica consiste en que la expresión entre
paréntesis que sigue al while
controla la ejecución de la
sentencia siguiente (pueden ser múltiples sentencias encerradas
entre llaves). Mientras la expresión entre paréntesis (en este
caso getline(in, s)
produzca un resultado
«verdadero», las sentencias controladas por el
while
se ejecutarán. getline()
devuelve un valor que se puede interprer como
«verdadero» si se ha leido otra línea de forma
satisfactoria, y «falso» cuando se llega al final de
la entrada. Eso implica que el while
anterior
lee todas las líneas del fichero de entrada y las envía al fichero
de salida.
getline()
lee los caracteres de cada línea
hasta que descubre un salto de línea (el carácter de terminación
se puede cambiar pero eso no se verá hasta el capítulo sobre
iostreams
del Volumen 2). Sin embargo,
descarta el carácter de nueva línea y no lo almacena en el objeto
string
. Por lo que si queremos copiar el
fichero de forma idéntica al original, debemos añadir el carácter
de nueva línea como se muestra arriba.
Otro ejemplo interesante es copiar el fichero entero en un único
objeto string
:
//: C02:FillString.cpp // Read an entire file into a single string #include <string> #include <iostream> #include <fstream> using namespace std; int main() { ifstream in("FillString.cpp"); string s, line; while(getline(in, line)) s += line + "\n"; cout << s; } ///:~
Listado 2.9. C02/FillString.cpp
Debido a la naturaleza dinámica de los
strings
, no hay que preocuparse de la
cantidad de memoria que hay que reservar para el
string
. Simplemente hay que añadir cosas y
el string
irá expandiéndose para dar cabida
a lo que le introduzca.
Una de las cosas agradables de poner el fichero entero en una
cadena es que la clase string
proporciona
funciones para la búsqueda y manipulación que le permiten
modificar el fichero como si fuera una simple línea. Sin embargo,
tiene sus limitaciones. Por un lado, a menudo, es conveniente
tratar un fichero como una colección de líneas en vez de un gran
bloque de texto. Por ejemplo, si quiere añadir numeración de
líneas es mucho más fácil si tiene un objeto
string
distinto para cada línea. Para
realizarlo, necesitamos otro concepto.
[37]
Actualmente existen variantes de
getline()
, que se discutirán profusamente
en el capítulo de iostreams
en el
Volumen 2