Clases para manejar ficheros en C++

Existen tres clases para manejar ficheros: ifstream, ofstream y fstream. La primera está orientada a ficheros de entrada, la segunda a ficheros de salida, y la tercera puede manejar cualquiera de los dos tipos o ficheros de entrada y salida.

Clase ifstream:

El constructor está sobrecargado para poder crear streams de varias maneras:

ifstream();
ifstream(const char *name, int mode = ios::in, 
   int = filebuf::openprot);

El primero sólo crea un stream de entrada pero no lo asocia a ningún fichero. El segundo lo crea, lo asocia al fichero con el nombre "name" y lo abre.

Los parámetros son: el nombre del fichero, el modo, que para ifstream es ios::in por defecto. El tercer parámetro se refiere al buffer, y no nos preocupa de momento.

Clase ofstream:

Lo mismo pasa con ofstream, salvo que los valores por defecto de los parámetros son diferentes:

ofstream();
ofstream(const char *name, int mode = ios::out, 
   int = filebuf::openprot);

Clase fstream:

fstream();
fstream(const char *name, int mode = ios::in, 
   int = filebuf::openprot);

Método open:

Todas estas clases disponen además del método "open", para abrir el fichero a lo largo de la ejecución del programa.

void open(const char *name, int mode,
   int prot=filebuf::openprot);

"name" es el nombre del fichero, mode es el modo en que se abrirá, puede ser uno o una combinación del tipo enumerado open_mode, de la clase "ios":

enum open_mode { in, out, ate, app, trunc, nocreate, 
   noreplace, binary };

Cada uno de los valores se pueden combinar usando el operador de bits OR (|), y significan lo siguiente:

  • in: modo de entrada.
  • out: modo de salida.
  • ate: abre el fichero y sitúa el cursor al final.
  • app: modo append, parecido al anterior, pero las operaciones de escritura siempre se hacen al final del fichero.
  • trunc: si se aplica a ficheros de salida, se creará el fichero si no existe previamente, o se truncará con un tamaño de 0 bytes, si existe.
  • nocreate: impide crear un fichero si no existe, en ese caso, la función falla.
  • noreplace: lo ignoro.
  • binary: abre el fichero en modo binario.

Los tres últimos modos probablemente no son estándar, y es posible que no existan en muchos compiladores.

Método close:

void close();

Sencillamente, cierra el fichero asociado a un stream.

Operador >>:

Igual que sucede con el stream estándar cout, el operador de flujo de salida >> se puede usar con streams de salida cuando trabajemos con texto.

Operador <<:

Del mismo modo, al igual que sucede con el stream estándar cin, el operador de flujo de entrada << se puede usar con streams de entrada cuando trabajemos con texto.

Método de salida put:

ostream& put(char ch);

Sirve para cualquier stream de salida, e inserta un carácter en el stream.

Método de entrada get:

int get();
istream& get(char*, int len, char = '\n');
istream& get(char&);
istream& get(streambuf&, char = '\n');

La primera forma no se recomienda y se considera obsoleta, lee un carácter desde el stream de entrada.

La segunda lee caracteres y los almacena en el buffer indicado en el primer parámetro hasta que se leen "len" caracteres o hasta que se encuentra el carácter indicado en el tercer parámetro, que por defecto es el retorno de línea.

La tercera forma extrae un único carácter en la referencia a char proporcionada.

La cuarta no nos interesa de momento.

Método de entrada getline:

istream& getline(char*, int, char = '\n');

Extrae caracteres hasta que se encuentra el delimitador y los coloca en el buffer, elimina el delimitador del stream de entrada y no lo añade al buffer.

Método eof:

int eof();

Verifica si se ha alcanzado el final del fichero, devuelve un valor nulo si no es así.

Método clear:

void clear(iostate state=0);

Cada vez que se produzca una condición de error en un stream es necesario eliminarla, ya que en caso contrario ninguna operación que se realice sobre él tendrá éxisto. Por ejemplo, si llegamos hasta el final de fichero, el stream quedará en estado "eof" hasta que se elimine explícitamente ese estado. Eso se hace mediante el método "clear", sin parámetros dejará el estado en 0, es decir, sin errores.

Los estados posibles se definen en un enumerado:

enum io_state ;
  • goodbit: indica que el estado es correcto.
  • eofbit: indica que se ha detectado fin de fichero.
  • failbit: indica que una operación sobre el stream ha fallado.
  • badbit: se activa si falla una operación de escritura de buffers.

Método bad:

int bad();

Devuelve el estado del bit "badbit".

Método fail:

int fail();

Devuelve el estado del bit "failbit".

Método good:

int good();

Devuelve el estado del bit "goodbit".

Ejemplo:

Veamos el ejemplo anterior de mostrar dos veces un fichero, pero esta vez escrito para C++ usando streams:

// ejemplo1.cpp: Muestra un fichero dos veces.
#include <iostream>
#include <fstream>
using namespace std;

int main() {
   ifstream fichero("ejemplo1.cpp");
   char c;
   
   while(fichero.get(c)) cout.put(c);
   fichero.clear(); // (1)
   fichero.seekg(0);
   while(fichero.get(c)) cout.put(c);
   fichero.close();
   cin.get();
   return 0;
}

Como vemos en (1), es necesario eliminar el bit de eof, que se ha activado al leer hasta el final del fichero, cuando el último intento de llamar a "get" ha fallado, porque se ha terminado el fichero.

Método is_open:

int is_open();

Devuelve un valor no nulo si el fichero está abierto.

Método flush:

ostream& flush();

Realiza las operaciones de escritura pendientes que aún se han realizado sólo en el buffer.

Métodos relacionados con acceso aleatorio.

Disponemos de otro tipo enumerado en ios para indicar movimientos relativos dentro de un stream de acceso aleatorio:

enum seek_dir ;
  • beg: relativo al principio del fichero.
  • cur: relativo a la posición actual del cursor dentro del fichero.
  • end: relativo al final del fichero.

Método seekg:

Cambia la posición del cursor en streams de entrada.

istream& seekg(streampos pos);
istream& seekg(streamoff offset, seek_dir dir);

La primera forma es para cambiar la posición de modo absoluto. La segunda para cambios relativos, en la que se indica el salto en el primer parámetro y el punto de partida en el segundo, que puede ser cualquiera de los indicados anteriormente: ios::beg, ios::cur o ios::end.

Método seekp:

Cambia la posición del cursor en streams de salida.

ostream& seekp(streampos pos);
ostream& seekp(streamoff offset, seek_dir);

Lo mismo que seekg, pero aplicado a estream de salida.

Método tellg:

streampos tellg();

Devuelve la posición actual del cursor dentro de un stream de entrada.

Método tellp:

streampos tellp();

Devuelve la posición actual del cursor dentro de un stream de salida.

Método read:

istream& read(char*, int);

Lee el número de caracteres indicado en el segundo parámetro dendro del buffer suministrado por el primero.

Método gcount:

int gcount();

Devuelve el número de caracteres sin formato de la última lectura. Las lecturas sin formato son las realizadas mediante las funciones get, getline y read.

Método write:

ostream& write(const char*, int);

Escribe el número de caracteres indicado en el segundo parámetro desde el buffer suministrado por el primero.

Ejemplo:

De nuevo haremos el ejemplo de copiar ficheros, pero esta vez usando streams.

// copia.cpp: Copia de ficheros
// Uso: copia <fichero_origen> <fichero_destino>

#include <iostream>
#include <fstream>
using namespace std;

int main(int argc, char **argv) {
    ifstream entrada;
    ofstream salida;
    
    char buffer[2048]; // Buffer de 2 Kbytes
    int bytesLeidos;

    if(argc != 3) {
       printf("Usar: copia <fichero_origen> <fichero_destino>\n");
       return 1;
    }

    // Abrir el fichero de entrada en lectura y binario
    entrada.open(argv[1]); 
    if(!entrada.good()) {
       printf("El fichero %s no existe o no puede ser abierto.\n", argv[1]);
       return 1;
    }
    // Crear o sobreescribir el fichero de salida en binario
    salida.open(argv[2]); 
    if(!salida.good()) {
       printf("El fichero %s no puede ser creado.\n", argv[2]);
       entrada.close();
       return 1;
    }
    // Bucle de copia:
    do {
       entrada.read(buffer, 2048);
       bytesLeidos = entrada.gcount();
       salida.write(buffer, bytesLeidos);
    } while(bytesLeidos > 0);
    // Cerrar ficheros:
    entrada.close();
    salida.close();
    return 0;
}

Comentarios de los usuarios (1)

Antonio
2013-01-16 11:27:47

Espero que esto sea de utilidad.

Por lo que veo noreplace no forma parte del estándar actual, su aplicación era la de evitar sobre escribir un archivo existente.

doc. al respecto:

http://msdn.microsoft.com/en-us/library/aa277521(v=VS.60).aspx

http://msdn.microsoft.com/es-es/library/aa984818(v=vs.71).aspx