5.4. Iostreams de fichero

Manipular ficheros con iostream es mucho más fácil y seguro que usar stdio en C. Todo lo que tiene que hacer es crear un objeto - el constructor hace el trabajo. No necesita cerrar el fichero explícitamente (aunque puede, usando la función miembro close()) porque el destructor lo cerrará cuando el objeto salga del ámbito. Para crear un fichero que por defecto sea de entrada, cree un objeto ifstream . Para crear un fichero que por defecto es de salida, cree un objeto ofstream. Un fstream puede hacer ambas cosas.

Las clases de stream de fichero encajan dentro de las clases iostream como se muestra en la siguiente figura:

Como antes, las clases que usted usa en realidad son especializaciones de plantillas definidas por definiciones de tipo. Por ejemplo, ifstream, que procesa ficheros de char, es definida como:

typedef basic_ifstream<char> ifstream;

5.4.1. Un ejemplo de procesado de fichero.

Aqui tiene un ejemplo que muestra algunas de las características discutidas antes. Nótese que la inclusión de <fstream> para delarar las clases de fichero de E/S. Aunque en muchas plataformas esto también incluye <iostream> automáticamente, los compiladores no están obligados a hacer esto. Si usted quiere compatibilidad, incluya siempre ambas cabeceras.

//: C04:Strfile.cpp
// Stream I/O with files;
// The difference between get() & getline().
#include <fstream>
#include <iostream>
#include "../require.h"
using namespace std;

int main() {
  const int SZ = 100; // Buffer size;
  char buf[SZ];
  {
    ifstream in("Strfile.cpp"); // Read
    assure(in, "Strfile.cpp"); // Verify open
    ofstream out("Strfile.out"); // Write
    assure(out, "Strfile.out");
    int i = 1; // Line counter

    // A less-convenient approach for line input:
    while(in.get(buf, SZ)) { // Leaves \n in input
      in.get(); // Throw away next character (\n)
      cout << buf << endl; // Must add \n
      // File output just like standard I/O:
      out << i++ << ": " << buf << endl;
    }
  } // Destructors close in & out

  ifstream in("Strfile.out");
  assure(in, "Strfile.out");
  // More convenient line input:
  while(in.getline(buf, SZ)) { // Removes \n
    char* cp = buf;
    while(*cp != ':')
      ++cp;
    cp += 2; // Past ": "
    cout << cp << endl; // Must still add \n
  }
} ///:~

Listado 5.5. C04/Strfile.cpp


La creación tanto del ifstream como del ofstream están seguidas de un assure() para garantizar que el fichero ha sido abierto exitosamente. El objeto resultante, usado en una situación donde el compilador espera un resultado booleano, produce un valor que indica éxito o fracaso.

El primer while demuestra el uso de dos formas de la función get(). La primera toma los carácteres dentro de un buffer y pone un delimitador cero en el buffer cuando bien SZ-1 carácteres han sido leidos o bien el tercer argumento (que por defecto es '\n') es encontrado. La función get() deja el carácter delimitador en el stream de entrada, así que este delimitador debe ser eliminado via in.get() usando la forma de get() sin argumentos. Puede usar tambien la función miembro ignore(), que tiene dos parámetros por defecto. El primer argumento es el número de carácteres para descartar y por defecto es uno. El segundo argumento es el carácter en el que ignore() se detiene (después de extraerlo) y por defecto es EOF.

A continuación, se muestran dos sentencias de salida similares: una hacia cout y la otra al fichero de salida. Nótese la conveniencia aquí - no necesita preocuparse del tipo de objeto porque las sentencias de formateo trabajan igual con todos los objetos ostream. El primero hace eco de la linea en la salida estándar, y el segundo escribe la línea hacia el fichero de salida e incluye el número de línea.

Para demostrar getline(), abra el fichero recién creado y quite los números de linea. Para asegurarse que el fichero se cierra correctamente antes de abrirlo para la lectura, usted tiene dos opciones. Puede envolver la primera parte del programa con llaves para forzar que el objeto out salga del ámbito, llamando así al destructor y cerrando el fichero, que es lo que se hace aquí. Tambien puede l lamar a close() para ambos ficheros; si hace esto, puede despues rehusar el objeto de entrada llamando a la función miembro open().

El segundo while muestra como getline() borra el caracter terminador (su tercer argumento, que por defecto es '\n') del stream de entrada cuando este es encontrado. Aunque getline(), como get(), pone un cero en el buffer, este todavía no inserta el carácter de terminación.

Este ejemplo, así como la mayoría de ejemplos en este capítulo, asume que cada llamada a alguna sobrecarga de getline() encontrará un carácter de nueva línea. Si este no es el caso, la estado eofbit del stream será activado y la llamada a getline() retornará falso, causando que el programa pierda la última línea de la entrada.