Entrada y salida A vueltas con el flujo (cin cout), vamos a ver un uso mas extendido del habitual. De paso conoceremos algunas de las trampas que nos esperan con los flujos, sobre todo por el tema de buffers. Veamos este ejemplo comentado
/** * Flujos.cpp * Programa para mostrar el uso de flujos * * Pello Xabier Altadill Izura * Compilacion: g++ -o Flujos Flujos.cpp */ using namespace std; #include <iostream> // Disponemos de varios flujos: // cin : para la entrada de distintis tipos de datos (std input) // cout : para la salida de distintos tipos de datos (std output) // cer: para la salida de errores (std error) // clo: para la salida de errores y redireccion a ficheros tipo log // cin utiliza buffers y nos podemos llevar sorpresas al recoger datos // si el usuario no los mete bien. Por ejemplo si se pide una palabra y se meten // dos, la siguiente vez que se pida otro dato se tomara el que se habia metido! // lo podemos evitar con cin.ignore // Funcion principal int main () { unsigned int i; char nombre_apellidos[25]; char linea[80]; int entero; char caracter; // ATENCION // hay que tener cuidado con los strings. prueba a meter nombre y apellido // y veras que el string solo se llena hasta el primer espacio en blanco, // o incluso para a la siguiente variable i y el programa casca. cout << "Mete tu nombre y tu apellido resalao: " << endl; cin >> nombre_apellidos; cout << "Tu nombre y apellidos: " << nombre_apellidos << endl; // con esta llamada evitamos que se tome en cuenta las sobras cin.ignore(255,'\n'); // Entrada multiple! cout << "Mete una palabra y un numero entero" << endl; cin >> nombre_apellidos >> entero; cout << "El texto: " << nombre_apellidos << " y el entero: " << entero << endl; // explicacion: >> es un operador que se puede sobrecargar como hemos visto // anteriormente: la expresion cin >> nombre_apellidos devuelve otro objeto iostream // y se podria reescribir asi: (cin >> nombre_apellidos) >> entero; // cin.get(string,tamaño) para recoger string completos cout << " Mete un string largo con espacios. " << endl; cin.getline(linea,80); cout << "resultado: " << linea << endl; // hay veces que puede interesar ignorar un numero de caracteres hasta llegar al final // de la linea, para eso podemos usar la funcion cin.ignore(70,'\n'); en lugar de \n // podemos usar cualquier caracter de terminacion que nos interese. // no hay que olvidar que cin es un buffer. Que pasa si solo queremos leer un caracter // sin tener que 'sacarlo' del buffer? podemos usar cin.peek() y si queremos meter // un caracter podemos usar cin.putback('.') -meteria un . en el buffer de cin // cin.get() tomando un unico caracter. Si metemos mas imprimira todos // puede usarse parametrizado: cin.get(caracter) cout << "Vete metiendo caracteres. termina con un ." << endl; while ( (caracter = cin.get()) != EOF) { if ( cin.peek() == '.' ) { cout << "nos vamos" << endl; break; } cout << caracter; } cin.ignore(255,'\n'); return 0; } |
/** * FlujosOut.cpp * Programa para mostrar el uso de flujos de SALIDA * * Pello Xabier Altadill Izura * Compilacion: g++ -o FlujosOut FlujosOut.cpp */ using namespace std; #include <iostream> // cout tambien utiliza buffers y nos podemos llevar sorpresas al recoger datos // aunque si queremos tirar de la cadena ejecutamos: cout << flush; // Funcion principal int main () { unsigned int i; char nombre_apellidos[25]; char linea[80]; int entero; char caracter; char frase[] = "Clatu verata nictu\n"; // si en cin teniamos get aqui tenemos: put // mandamos un saludo cout.put('K').put('a').put('i').put('x').put('o').put('\n'); // vamos a mostrar una linea: entero = strlen(frase); // con esto la mostramos entera cout.write(frase,entero); // con esto... no cout.write(frase, (entero-5)); cout << " ahora con formato: " << endl; // vamos a ponerla con cierto formato: width y fill cout.width(30); // esto mete espacios en blanco equivalente = setw(30) cout << frase << endl; cout.width(50); // esto vuelve a meter espacios cout.fill('>'); // y esto RELLENA los ESPACIOS cout << frase << endl; // Estableciendo el estado de cout con setf // alineacion: setf(ios::left) y setf(ios::right) // hay mas, para investigar: ios::showbase, ios::internal, etc... cout.setf(ios::right); entero = 666; // podemos alterar la base con dec, oct y hex cout << "entero hexadecimal alineado a la derecha: " << hex << entero << endl; return 0; } |
/** * Fichero.hpp * Clase que define el objeto Fichero, un objeto que sirve gestionar un fichero * * Pello Xabier Altadill Izura * */ using namespace std; #include <iostream> #include <fstream> // atencion hay que incluir esto enum tipo_fichero { ENTRADA, SALIDA, APPEND }; class Fichero { public: Fichero(); Fichero(char *nombre, tipo_fichero tipo); ~Fichero(); Fichero(Fichero const &); char *getNombre() const { return this->nombre;} // operaciones sobre ficheros int cerrar () const; // cierra el fichero char leer() const; // lee del fichero void escribir (char linea[255]) const; // escribe linea private: // esta funcion decide que tipo de fichero iniciar void inicializaFichero(); tipo_fichero tipo; char *nombre; ofstream *saliente; ifstream *entrante; }; |
/** * Fichero.cpp * Programa que implementa la clase Fichero * * Pello Xabier Altadill Izura * Compilacion: g++ -o Fichero Fichero.cpp * */ #include "Fichero.hpp" // Constructor Fichero::Fichero(): nombre("test.txt"), tipo(ENTRADA) { inicializaFichero(); cout << "Fichero construido." << endl; } // Constructor Fichero::Fichero(char *nombre, tipo_fichero tipo) { this->nombre = nombre; this->tipo = tipo; inicializaFichero(); cout << "Fichero construido con nombre: " << nombre << endl; } // Destructor Fichero::~Fichero() { cout << "Fichero destruido." << endl; } // Constructor copia Fichero::Fichero(Fichero const & original) { nombre = new char; nombre = original.nombre; } // cierra el fichero int Fichero::cerrar () const { if (this->tipo == 0) { entrante->close(); } else { saliente->close(); } return 0; } // lee linea del fichero char Fichero::leer () const { return entrante->get(); } // escribir sobre el fichero void Fichero::escribir (char linea[255]) const { saliente->write(linea,255); } // esta funcion decide que tipo de fichero iniciar void Fichero::inicializaFichero() { switch (this->tipo) { case 0 : cout << "tipo ENTRADA" << endl; entrante = new ifstream(this->nombre); break; case 1 : cout << "tipo SALIDA" << endl; saliente = new ofstream(this->nombre); break; case 2 : cout << "tipo APPEND" << endl; saliente = new ofstream(this->nombre,ios::app); break; default : cout << "nada" << endl; break; } } // funcion principal, en la que de paso vemos // PARAMETROS de linea de comandos int main (int argc, char **argv) { int i; char temp; char linea[255]; // vamos a revisar los argumentos que se han pasado al programa for (i=0; i<argc; i++) { cout << "argumento (" << i << "): " << argv[i] << endl; } Fichero fichero = Fichero("prueba.txt",APPEND); cout << "escribe algo para añadir al fichero: "; cin.getline(linea,255); cout << "has puesto: " << linea << endl; fichero.escribir(linea); fichero.cerrar(); // leyendo de forma directa. Leemos el parametro que hayamos pasado ifstream leer("prueba.txt"); // abrimos el fichero leer.open("prueba.txt"); // recorremos el fichero y mostramos contenido while ( leer.get(temp) ) { // esto indica el final cout << temp; } // cerramos el fichero leer.close(); return 0; } |