Anuncios

Hola, sean bienvenidos a este post. Hoy continuaremos lo iniciado en el post anterior, seguiremos viendo flujos, en este caso empezaremos con printf(), continuaremos con manipulacion de archivos, y finalizaremos con parametros en lineas de comando. 

Anuncios

Empecemos a desarrollar los temas, primero hablemos sobre printf(), este es otro metodo para mostrar en pantalla la informacion heredado de C pero es conveniente saberlo porque mucha gente en el dia de hoy sigue utilizandolo pero no esta incluido dentro de la libreria iostream sino con la stdio.h, no olvide incluirla como hace con el resto de las librerias, veamos un poco su sintaxis y los especificadores:

printf("Especificador","Informacion");
Anuncios

Donde especificador indicara cual tipo de informacion es, y la informacion va a ser el mensaje a mostrar, veamos la siguiente tabla:

 EspecificadorUtilizado para
 %sCadena
 %dEnteros
 %ldEntero Largo
 %lfDoble
 %fFlotante
Anuncios

Mostrada su sintaxis y la funcion de cada especificador pasemos a ver un ejemplo:

flujos08.cpp

# include <stdio.h>

using namespace std;

int main()
{
 	printf("%s","Hola Mundo!\n");
	const char * frase = "Hola Mundo de Nuevo!\n";
 	printf("%s", frase);
	int x = 5;
 	printf("%d\n", x);
	const char * fraseDos = "He aqui algunos valores: ";
 	const char * fraseTres = " y aqui estan otros: ";
 	int y = 7, z = 35;
 	long longVar = 98456;
 	float floatVar = 8.8f;
 	printf("%s %d %d %s %ld %f\n", fraseDos, y, z, fraseTres, longVar, floatVar);
	const char * fraseCuatro = "Con formato: ";
 	printf("%s %5d %10d %10.5f\n", fraseCuatro, y, z, floatVar);
	return 0;
}
Anuncios

En este ejemplo vemos las distintas formas de mostrar en pantalla nuestra informacion por medio de printf(), en el primer ejemplo vemos al eterno ejemplo Hola Mundo, observen como primero especificamos el tipo y luego ingresamos la frase. En el segundo caso creamos una variable llamada frase donde almacenaremos un texto y observen como en printf() utilizamos el especificador y luego la variable. En el tercer caso utilizamos una variable de tipo entero pero al ser un numero no podremos utilizar el caracter de nueva linea (\n) en la variable pero como pueden ver lo especificamos detras del especificador para indicarle al printf() que una vez impreso debe pasar a la nueva linea, en el cuarto caso va a ser un poco mas complejo porque haremos una “concatenacion” de diferentes datos, en este caso vamos a crear dos variables de tipo char, dos de tipo int, una long y una float, analicemos la linea donde muestra la salida:

printf("%s %d %d %s %ld %f\n", fraseDos, y, z, fraseTres, longVar, floatVar);
Anuncios

Observen primero el segmento de los especificadores, debemos ubicarlos en el mismo orden a la informacion a mostrar, en este caso primero un especificador de tipo cadena, luego dos de tipo entero, despues otro de tipo cadena, por ultimo el valor doble y el valor  flotante, en el quinto caso es similar pero en este caso le damos formato, veamos la linea:

printf("%s %5d %10d %10.5f\n", fraseCuatro, y, z, floatVar);
Anuncios

Como pueden ver resalte los “formateadores”, porque en todos los casos formateara el ancho a mostrar y en el caso del flotante tambien le indicamos la cantidad a mostrar despues del punto, veamos la salida:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos08
Hola Mundo!
Hola Mundo de Nuevo!
5
He aqui algunos valores:  7 35  y aqui estan otros:  98456 8.800000
Con formato:      7         35    8.80000
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Hasta aca como funciona printf(), como pueden ver no tiene la posibilidad de concatenar como cout pero de cierta manera, mucho mas compleja tambien, se puede hacer. Como dije al principio, por ser heredada de C muchos programadores lo siguen utilizando y se lo pueden encontrar en algun codigo ajeno. Ahora pasemos a ver como se manipula archivos en C++, para manipular nuestros archivos utilizaremos dos metodos:

  • ofstream, para manipular lo salida a un archivo.
  • ifstream, para manipular la entrada de un archivo.

La forma de utilizar estos metodos es similar por eso mostrare una sola:

ofstream objeto("nombre de archivo");

Podriamos utilizarlo de esta forma:

ofstream fout("miarchivo.txt");
Anuncios

Veamos un ejemplo de como manipular un archivo:

flujos09.cpp

# include <fstream>
# include <iostream>

using namespace std;

int main()
{
 	char nombreArchivo[ 80 ];
 	char bufer[ 255 ];
	cout << "Nombre del archivo: ";
 	cin >> nombreArchivo;
	ofstream abrir(nombreArchivo);
 	abrir << "Este texto va directo para el archivo, dale gas PAPAAAAAA\n";
 	cout << "Escriba el texto para el archivo: ";
 	cin.ignore(1,'\n');
 	cin.getline(bufer,255);
 	abrir << bufer << endl;
 	abrir.close();
	ifstream leer(nombreArchivo);
 	cout << "\nAca va el contenido del archivo:\n ";
 	char ch;
 	while(leer.get(ch))
 		cout << ch;
 	cout << "\n+++ Final del archivo +++\n";
 	leer.close();
 	return 0;
}
Anuncios

Este es un ejemplo basico de como manipular un archivo, vamos a crear dos variables de tipo char, una para el nombre del archivo y otro para almacenar un texto, nuestra primera opcion es ingresar el nombre del archivo a crear, en el siguiente bloque veremos como llenar ese archivo, primero vamos a abrirlo, luego utilizamos el objeto creado con la clase ofstream y le ingresa una cadena de tipo constante, luego pondremos en pantalla una opcion para ingresar un texto adicional, observen como ignora primero lo ingresado en nombreArchivo, porque todavia esta en el buffer, y luego lo ingresado por medio de un getline() es almacenado en la variable bufer para luego ser guardado en el archivo, una vez terminado procedemos a cerrar el archivo. Con el archivo cerrado, creamos un objeto del tipo ifstream, en este caso llamado leer, y le indicamos el nombre almacenado en nombreArchivo, primero pondremos un indicador de donde empieza a mostrar el contenido, luego creamos una variable de tipo char, por medio de un bucle while() utilizamos el objeto leer por medio de un get(ch) donde extraera caracter por caracter y lo mostrara en pantalla y una vez finalizado nos mostrara un mensaje indicando el fiinal del mismo para cerrar el archivo, si lo compilamos y ejecutamos podemos tener una salida como la siguiente:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos09
Nombre del archivo: prueba.txt
Escriba el texto para el archivo: Hola, Mundo! Como estan?

Aca va el contenido del archivo:
 Este texto va directo para el archivo, dale gas PAPAAAAAA
Hola, Mundo! Como estan?

+++ Final del archivo +++
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver esta es la forma mas basica de como crear un archivo, ingresar un contenido y recuperarlo pero antes veamos un listado del directorio para ver como se genero nuestro archivo:

tinchicus@dbn001dsk:~/lenguaje/c++$ ls -l prueba.txt
-rw-r--r-- 1 tinchicus tinchicus 83 jul  6 20:40 prueba.txt
tinchicus@dbn001dsk:~/lenguaje/c++$ cat prueba.txt
Este texto va directo para el archivo, dale gas PAPAAAAAA
Hola, Mundo! Como estan?
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver se genero el archivo correctamente en el directorio y en el caso de Linux si usamos cat podemos ver el contenido del archivo. En el siguiente caso hablaremos un poco de como cambiar el comportamiento predeterminado de ofstream, esto se hace atraves de unos argumentos adicionales en el momento de crear el objeto, veamos un listado de algunos argumentos para manipular nuestros archivos:

  • ios::app, agrega el nuevo contenido al final del archivo, en lugar de eliminarlo.
  • ios::ate, lleva al final del archivo pero puede escribir en cualquier parte del mismo.
  • ios::trunc, es el predeterminado (cuando no se informa ninguno) y elimina los archivos existentes.
  • ios::nocreate, si el archivo no existe, falla al abrir el mismo.
  • ios::noreplace, si el archivo ya existe, falla en la apertura del mismo.
Anuncios

Estos son solo algunos argumentos pero como pueden ver para la mayoria de nuestros casos van a ser los mas utiles, pasemos a ver un ejemplo para verlos en accion:

flujos10.cpp

# include <fstream>
# include <iostream>

using namespace std;

int main()
{
 	char nombreArchivo[ 50 ];
 	char bufer[ 255 ];
	cout << "Ingresa el nombre de un archivo: ";
 	cin >> nombreArchivo;
	ifstream fin(nombreArchivo);
 	if (fin)
 	{
 		cout << "Contenido actual del archivo: \n";
 		char ch;
 		while(fin.get(ch))
 			cout << ch;
 		cout << "\n++++Final del archivo++++\n";
 	}
 	fin.close();
 	cout << "\n...Abriendo " << nombreArchivo;
 	cout << " en modo Agregar \n";
 	ofstream fout(nombreArchivo, ios::app);
 	if (!fout)
 	{
 		cout << "No se puede abrir " << nombreArchivo;
 		cout << " para agregar.\n";
 		return (1);
 	}
 	cout << "\nEscribe el texto para el archivo: ";
 	cin.ignore(1,'\n');
 	cin.getline(bufer,255);
 	fout << bufer << "\n";
 	fout.close();
 	fin.open(nombreArchivo);
 	if (!fin)
 	{
 		cout << "No se puede abrir " << nombreArchivo;
 		cout << " para lectura,\n";
 		return (1);
 	}
 	cout << "Aca tenemos el contenido del archivo: \n";
 	char ch;
 	while(fin.get(ch))
 		cout << ch;
 	cout << "\n++++ Final del archivo ++++\n";
 	fin.close();
 	return 0;
}
Anuncios

En este ejemplo primero ingresaremos el nombre del archivo, luego lo abriremos mediante el ifstream, luego chequearemos si se encontro el archivo mediante el condicional if, procedera a mostrar el contenido en el archivo y en caso contrario omitira el contenido del archivo, luego procede a abrir el archivo y lo hace en formato agregar (ios::app), si todo sale bien recibimos una notificacion para ingresar un nuevo texto, una vez ingresado cerramos el archivo y lo volvimos a abrir mediante el metodo open() del objeto fin para mostrar el resultado final del archivo les paso una salida de ejemplo:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos10
Ingresa el nombre de un archivo: prueba.txt
Contenido actual del archivo:
Este texto va directo para el archivo, dale gas PAPAAAAAA
Hola, Mundo! Como estan?

++++Final del archivo++++

…Abriendo prueba.txt en modo Agregar
Escribe el texto para el archivo: Este es un nuevo texto!
Aca tenemos el contenido del archivo:
Este texto va directo para el archivo, dale gas PAPAAAAAA
Hola, Mundo! Como estan?
Este es un nuevo texto!

++++ Final del archivo ++++
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Por medio del metodo open() no necesitamos volver a crear un objeto para abrir el archivo sino simplemente volver a redireccionar, mediante este metodo, de nuevo hacia el archivo. Hasta aqui hemos visto, como escribir, como leer y como agregar en un archivo, ahora veremos como tratar distintos tipos de archivos. En los ejemplos anteriores hemos manejado archivos de tipo texto pero tambien existen los de tipo binarios, la diferencia entre ambos radica en el tipo de informacion a guardar porque el de texto solamente guarda texto y el binario puede guardar una mayor cantidad de tipo de informacion, ademas de texto, para manipular utilizaremos tres metodos, write(), read() y sizeof(), escribir, leer y saber el tamaño, respectivamente, veamos a traves del siguiente ejemplo como funciona:

flujos11.cpp

# include <fstream>
# include <iostream>

using namespace std;

class Animal
{
public:
 	Animal(int peso, long dias):suPeso(peso), suNumeroDiasVivos(dias){}
 	~Animal(){}
 	int ObtenerPeso() const { return suPeso; }
 	void AsignarPeso(int peso) { suPeso = peso; }
 	long ObtenerDiasVivo() const { return suNumeroDiasVivos; }
 	void AsignarDiasVivos(long dias) { suNumeroDiasVivos = dias; }
private:
 	int suPeso;
 	long suNumeroDiasVivos;
};

int main()
{
 	char nombreArchivo[ 50 ];
	cout << "Escriba el nombre del archivo: ";
 	cin >> nombreArchivo;
	ofstream fout(nombreArchivo, ios::binary);
 	if (!fout)
 	{
 		cout << "No se puede abrir " << nombreArchivo;
 		cout << " para escritura.\n";
 		return (1);
 	}
	Animal Oso(50,100);
 	fout.write((char *) &Oso, sizeof Oso);
 	fout.close();
 	ifstream fin(nombreArchivo, ios::binary);
 	if (!fin)
 	{
 		cout << "No se puede abrir " << nombreArchivo;
 		cout << " para lectura.\n";
 		return (1);
 	}
	Animal OsoDos(1, 1);
 	cout << "OsoDos peso: " << OsoDos.ObtenerPeso() << endl;
 	cout << "OsoDos edad: " << OsoDos.ObtenerDiasVivo() << endl;
 	fin.read((char *) &OsoDos, sizeof OsoDos);
 	cout << "OsoDos peso: " << OsoDos.ObtenerPeso() << endl;
 	cout << "OsoDos edad: " << OsoDos.ObtenerDiasVivo() << endl;
 	return 0;
}
Anuncios

En este ejemplo veremos como utilizar un archivo del tipo binario, como siempre crearemos una variable donde indicaremos el nombre de nuestro archivo, despues utilizaremos el ofstream para crearlo pero le agregaremos como argumento ios::binary, luego tendremos un condicional if para chequear si se creo el archivo correctamente, de lo contrario sale del programa, en caso de existir el archivo creo un objeto de la clase Animal llamado Oso, luego mediante el write() copiamos todos los datos del objeto en el archivo, write() copia toda la informacion informada sin chequear su contenido (estos podrian ser todos nulls y lo copiaria igual), luego cerramos el archivo y lo volvemos a abrir pero con el metodo ifstream y tambien en modo binario, chequea si existe o no, si no existe procede a salir del programa y en caso de existir continua con el mismo,  en la siguiente linea crea otro objeto de la clase Animal llamado OsoDos donde le asigna otros valores distintos del objeto anterior, en las siguiente dos lineas obtenemos los valores del objeto OsoDos y los mostramos en pantalla, y a la siguiente linea, leemos los datos almacenados en el archivo y los asignamos a OsoDos, dando como resultado el reemplazo de los datos y al mostrarlos en pantalla van a ser los datos de Oso, esta es la salida del programa:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos11
Escriba el nombre del archivo: animal.txt
OsoDos peso: 1
OsoDos edad: 1
OsoDos peso: 50
OsoDos edad: 100
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Para nuestro ultimo caso vamos a hablar sobre el procesamiento de la linea de comandos, es decir poder leer los parametros informados al programa desde la linea de comandos, por ejemplo:

$./unprograma param1 param2 param3
Anuncios

Cuando trabajamos con parametros, estos no se pasan todos a main() sino solamente dos, la cantidad de parametros y un array con los mismos, consideremos esto de la linea anterior como ejemplo, en la linea no pasamos tres parametros sino cuatro porque el nombre del programa tambien se considera uno y este se envia siempre, es decir main() siempre tiene implicitamente el nombre del programa como un parametro, por lo tanto siempre tiene en cantidad uno y en el array de parametros el nombre del mismo, por convencion se los llama argc y argv, donde el primero almacena la cantidad de argumentos y en el segundo es un array de todos los argumentos pero como dijimos es por convencion y se les puede asignar otro nombre, veamos un ejemplo simple para clarificarlo un poco:

flujos12.cpp

# include <iostream>

using namespace std;

int main(int argc, char **argv)
{
 	cout << "Se recibieron " << argc << " argumentos...\n";
 	for(int i=0; i < argc; i++)
 		cout << "Argumento " << i << ": " << argv[i] << endl;
 	return 0;
}
Anuncios

Como pueden ver el ejemplo es bien simple, el verdadero truco esta en el main(), observen los dos nuevos argumentos receptores, uno de tipo int para almacenar la cantidad, argc, y luego uno de tipo char donde almacena los parametros, argv, en este caso esta definido como apuntador de un apuntador pero tambien se podria haber utilizado char *argv[] o char argv[][], en todos los casos hace trabajar a este argumento como un array. luego tenemos una linea donde muestra la cantidad y un bucle for donde nos muestra cada uno de los argumentos, veamos dos salidas de ejemplos, una sin parametros y otra con parametros:

Sin parametros:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos12
Se recibieron 1 argumentos…
Argumento 0: ./flujos12
tinchicus@dbn001dsk:~/lenguaje/c++$

Con parametros:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos12 Hola mundo ! como estan ?
Se recibieron 7 argumentos…
Argumento 0: ./flujos12
Argumento 1: Hola
Argumento 2: mundo
Argumento 3: !
Argumento 4: como
Argumento 5: estan
Argumento 6: ?
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver siempre va a haber un parametro para el main(), ahora veremos un ejemplo modificando el ultimo codigo cuando trabajamos con archivos binarios pero en lugar del programa pedirnos un nombre de archivo, nosotros se lo informaremos por la linea de comando, pasemos a ver el nuevo ejemplo:

flujos13.cpp

# include <fstream>
# include <iostream>

using namespace std;

class Animal
{
public:
 	Animal(int peso, long dias):suPeso(peso), suNumeroDiasVivos(dias){}
 	~Animal(){}
 	int ObtenerPeso() const { return suPeso; }
 	void AsignarPeso(int peso) { suPeso = peso; }
 	long ObtenerDiasVivo() const { return suNumeroDiasVivos; }
 	void AsignarDiasVivos(long dias) { suNumeroDiasVivos = dias; }
private:
 	int suPeso;
 	long suNumeroDiasVivos;
};

int main(int paramc, char *paramv[])
{
	if (paramc<2)
	{
		cout << "Uso: " << paramv[0];
		cout << " [nombredearchivo]" << endl;
		return (1);
	}

	ofstream fout(paramv[1], ios::binary);
 	if (!fout)
 	{
 		cout << "No se puede abrir " << paramv[1];
 		cout << " para escritura.\n";
 		return (1);
 	}
	Animal Oso(50,100);
 	fout.write((char *) &Oso, sizeof Oso);
 	fout.close();
 	ifstream fin(paramv[1], ios::binary);
 	if (!fin)
 	{
 		cout << "No se puede abrir " << paramv[1];
 		cout << " para lectura.\n";
 		return (1);
 	}
	Animal OsoDos(1, 1);
 	cout << "OsoDos peso: " << OsoDos.ObtenerPeso() << endl;
 	cout << "OsoDos edad: " << OsoDos.ObtenerDiasVivo() << endl;
 	fin.read((char *) &OsoDos, sizeof OsoDos);
 	cout << "OsoDos peso: " << OsoDos.ObtenerPeso() << endl;
 	cout << "OsoDos edad: " << OsoDos.ObtenerDiasVivo() << endl;
 	return 0;
}
Anuncios

Este codigo es exactamente al explicado en manipulacion de archivos, las unicas diferencias van a estar en el main() donde le agregamos los siguientes parametros:

int main(int paramc, char *paramv[])

Como dijimos antes argc y argv son por convencion, en este caso les cambie los nombres y funciono perfectamente aunque lo recomendable es respetar la convencion pero como digo habitualmente queda al criterio de cada programador. Nuestra siguiente modificacion va a ser esta:

	if (paramc<2)
	{
		cout << "Uso: " << paramv[0];
		cout << " [nombredearchivo]" << endl;
		return (1);
	}
Anuncios

Donde verificara la cantidad de argumentos, si la cantidad es menor a dos procedera a mostrarnos un mensaje de error y salir del programa, este bloque reemplazara a este del codigo anterior:

char nombreArchivo[ 50 ];
cout << "Escriba el nombre del archivo: ";
cin >> nombreArchivo; 
Anuncios

Este era el bloque donde nos solicitaba el nombre para el archivo pero como nosotros lo informamos por la linea de comando ya no es necesario, con el nombre enviado por linea de comandos el programa continua y modificaremos algunas lineas, es decir donde estaba nombreArchivo, ahora se reemplazara con el segundo valor contenido en el array de parametros (paramv[ 1 ]) y sera utilizado para escribir el archivo, para leerlo y/o mostrar el nombre en caso de error, veamos la salida de error y la salida correcta:

Salida con error:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos13
Uso: ./flujos13 [nombredearchivo]
tinchicus@dbn001dsk:~/lenguaje/c++$

Salida correcta:

tinchicus@dbn001dsk:~/lenguaje/c++$ ./flujos13 oso.txt
OsoDos peso: 1
OsoDos edad: 1
OsoDos peso: 50
OsoDos edad: 100
tinchicus@dbn001dsk:~/lenguaje/c++$
Anuncios

Como pueden ver el programa funciono correctamente, hasta aqui todo lo relacionado con la recepcion de parametros a traves de la linea de comandos, esto es util porque habitualmente para este tipo de programas se utiliza mas este metodo, en lugar de estar solicitando al usuario el ingreso de los datos pero tambien se puede hacer un programa intermedio, es decir que tenga la posibilidad de recibir todos los parametros o en caso de no tenerlo te los solicite, hasta aqui hemos llegado con flujos hagamos un breve resumen de lo visto hoy:

printf

  • Es un metodo heredado de C
  • Tambien sirve para mostrar salida en pantalla
  • Su estructura es, primero especificador y luego informacion
  • No permite concatenar directamente, es un poco mas complejo a diferencia de cout.
  • Sigue siendo utilizado por la mayoria de los programadores.
Anuncios

ofstream

  • Es utilizado para escribir archivos en el disco
  • Podemos cambiar su comportamiento con parametros
  • Podemos usarlo de tipo texto o binario
  • Utiliza el metodo write() cuando necesita escribirlo en binario
  • En modo texto se puede utilizar el operador << para escribirlo
Anuncios

ifstream

  • Es utilizado para leer un archivo del disco
  • Utiliza read() para leer archivos binarios
  • Puede utilizar el metodo get() para leer archivos en modo texto
  • Utiliza open() para abrir otro archivo por el mismo objeto creado
Anuncios

parametros de linea de comando

  • Estan implicitos en el main()
  • Solamente se utilizan dos argumentos.
  • Uno es para la cantidad de parametros, el otro es el array con todos los parametros
  • El nombre del programa esta en la primera ubicacion del array de parametros
  • A partir de la segunda ubicacion estan el resto de los parametros.
Anuncios

Hasta aqui llego el post, en el dia de hoy hemos visto como utilizar el metodo printf(), hemos visto como manipular archivos desde su creacion hasta como leer su contenido, tambien para archivos de tipo binario, y por ultimo hemos visto como pasar parametros a traves de la linea de comandos a nuestros programas,  si necesitan un claro ejemplo de como trabajar con estos argumentos les recomiendo estos tres posts:

Anuncios

Porque en esos posts vamos desarrollando un programa similar al cliente de mysql, donde entre otras cosas nos permite el envio de parametros de ingreso a traves de la linea de comando y con lo explicado hoy queda un poco mas claro como funciona, la manipulacion de archivos es algo muy practico para los lenguajes porque nos permite almacenar algunos tipos de informacion para futuros usos, me paso especialmente en Qbasic cuando aprendi a dominar el uso de archivos aparecio ante mi un nuevo mundo sin limites, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Tengo un Patreon donde podes acceder de manera exclusiva a material para este blog antes de ser publicado, sigue los pasos del link para saber como.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00