Entrada/Salida

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&ntilde;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;

}

En este otro se habla mas de cout

/**
* 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;
}

Ficheros en c++ Oh si, podemos manejar ficheros de entrada/salida con las clases mas std. veamos unos ejemplos, metidos dentro de un objeto. Es bastante mejorable.

/**
* 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;

};

Y su implementacion.

/**
* 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&ntilde;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;

}