Anuncios

Bienvenidos sean a este post, hoy veremos el concepto de «procesar» un archivo..

Anuncios
Anuncios

En el post anterior vimos como podemos manejar archivos ya sea tanto para escritura como para lectura, en los ejemplos vistos en ese post definimos un nombre para el archivo y el contenido que almacenara tanto a traves del programa y luego por medio del prompt le pasabamos el nombre que debia usar el archivo y en caso de omision procedia a indicarnos como debiamos usar el programa, pero que es el procesamiente de archivos? En realidad esta mas enfocado al formato de nuestros archivos, ya que cada programa tiene su propio formato de archivo, por ejemplo Excel, y el programa se encarga tanto de leer como de escribirlo en su forma correcta, si bien existen tantas tecnicas como programas en cualquier lenguaje por lo general se reducen a dos forma muy basicas como son:

  • Acceso secuencial
  • Acceso random
Anuncios
Anuncios

Si bien esto es una forma de sobresimplificar las capacidades que disponemos del lenguaje porque a su vez estan compuestas por mas modos y formas de trabajar, para entenderlo mejor vamos a crear un ejemplo simple con algunas bases de lo visto anteriormente pero orientado a otros temas, en este caso vamos a crear un programa que podra generar un archivo donde almacenara un listado de nombres ya sea ingresado por medio de stdin como de otro archivo, con todo comentado pasemos a crear el ejemplo y para ello primero crearemos un directorio llamado archivos y dentro de este crearemos dos mas llamado libs y files, veamos como debe quedar la estructura de nuestro directorio:

archivos/
├── files
└── libs
Anuncios

En el directorio archivos crearemos un archivo con el nombre de program.c y le agregaremos el siguiente codigo:

program.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>

void usar(char* cmd)
{
	fprintf(stderr, "uso: %s [-i entrada] [-o salida]\n", cmd);
	fprintf(stderr, "si no se informa -i, se usa stdin\n");
	fprintf(stderr, "si no se informa -o, se usa stdout\n");
	exit(EXIT_FAILURE);
}

int main(int argc, char* argv[])
{
	int c;
	FILE* entrada = NULL;
	FILE* salida = NULL;

	while((c = getopt(argc, argv, "i:o:h")) != -1)
	{
		switch(c)
		{
			case 'i':
				if (NULL==(entrada=fopen(optarg,"r")))
				{
					fprintf(stderr,
						"archivo entrada \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr,"usando \"%s\" para entrada\n",
					optarg);
				break;
			case 'o':
				if (NULL==(salida=fopen(optarg,"a")))
				{
					fprintf(stderr,
						"archivo salida \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr, "usando \"%s\" para salida\n",
					optarg);
				break;
			case '?':
			case 'h':
			default:
				usar(argv[0]);
				break;
		}
	}

	if (!entrada)
	{
		entrada = stdin;
		fprintf(stderr, "usando stdin para entrada\n");
	}

	if (!salida)
	{
		salida =stdout;
		fprintf(stderr, "usando stdout para salida\n");
	}

	fprintf(stderr, "Hace el trabajo aqui\n");

	fprintf(stderr,"Cerrando archivos\n");
	fclose(entrada);
	fflush(salida);
	fclose(salida);

	return 0;
}
Anuncios
Anuncios

Primero vamos a incluir unas cuantas librerias, algunas de las cuales ya hemos usado en otros casos, despues diremos que funcion viene de tal libreria, lo siguiente sera una funcion para indicar como debemos usar el programa y en caso de omitir los archivos de entrada y/o salida nos indica cual usaremos en reemplazo, en el main definiremos tres variables, la primera sera para las opciones ue ingresemos, las siguientes seran para manejar el archivo de entrada y de salida, lo siguiente sera un bucle while donde usaremos a getopt para determinar cual opcion ingresamos y esto lo haremos si es distinto de -1, despues por medio de un switch captaremos cada una de las opciones, la primera opcion sera para el i, vamos a analizar primero este bloque:

case 'i':
	if (NULL==(entrada=fopen(optarg,"r")))
	{
		fprintf(stderr,
			"archivo entrada \"%s\": %s\n",
			optarg, strerror(errno));
		exit(EXIT_FAILURE);
	}
	fprintf(stderr,"usando \"%s\" para entrada\n",
		optarg);
	break;
Anuncios
Anuncios

En este caso procesaremos la opcion de i, en caso de encontrarse lo primero que hara sera chequear si el valor almacenado en entrada es igual a NULL, en entrada almaceanremos el resultado de abrir el archivo que informamos como argumento, en caso de ser asi mostraremos en el stream de error el archivo y el error relacionado a este, despues usaremos a exit para salir del programa con EXIT_FAILURE, en caso de no usarse el condicional mostraremos cual sera el archivo que usaremos de entrada, la siguiente opcion es o y hace exactamente lo mismo pero con la letra o y el archivo de salida, por ultimo tenemos dos case y el default para llamar a la funcion usar que usaremos para describir como debemos usar al programa, es decir que sera nuestras opciones de ayuda, lo siguiente sera un condicional donde chequearemos si entrada esta vacio, en caso de ser asi le asignaremos a stdin para utilizarlo, y lo mostraremos, lo mismo haremos en el siguiente condicional pero para salida y en ese caso usaremos a stdout, para finalizar mostraremos un mensaje para indicar que «estamos trabajando» y que «cerraremos los archivos» para finalmente cerrar todo, veamos como funciona este codigo mediante el siguiente video

Anuncios

En el video podemos ver primero como crear dos archivos vacios en nuestro directorio files, esto lo hacemos asi porque en un momento trabajaremos con ellos, touch simplemente crea el archivo sin contenido convirtiendolo en una herramienta muy practica en Linux, despues vemos las distintas conductas de nuestro codigo con las distintas opciones, con esto tenemos la base de nuestro codigo, nuestro siguiente paso sera crear las primeras funciones para poder trabajar, para ello debemos hacer algunas modificaciones, en este caso primero agregaremos el siguiente segmento de codigo antes del main:

const int max_cadena=80;

void usar(char* cmd);
int getNombre(FILE* entradaDesc, char* aCdn);
void putNombre(char* aCdn, FILE* salidaDesc);
int trimCdn(char* aCdn);
Anuncios

Primero definiremos una constante para establecer el maximo de una cadena, despues declareremos cuatro prototipos para distintas funciones, el primero ya lo tenemos definido solamente debemos tomar ese bloque de codigo y pasarlo por detras del main, despues tendremos tres funciones para obtener y poner un nombre y una que nos hara el mismo resultado que la funcion trim de otros lenguajes, esta elimina los espacios en blanco delante y detras del texto, veamos como quedo nuestro codigo:

program.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>

const int max_cadena=80;

void usar(char* cmd);
int getNombre(FILE* entradaDesc, char* aCdn);
void putNombre(char* aCdn, FILE* salidaDesc);

int main(int argc, char* argv[])
{
	int c;
	FILE* entrada = NULL;
	FILE* salida = NULL;

	while((c = getopt(argc, argv, "i:o:h")) != -1)
	{
		switch(c)
		{
			case 'i':
				if (NULL==(entrada=fopen(optarg,"r")))
				{
					fprintf(stderr,
						"archivo entrada \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr,"usando \"%s\" para entrada\n",
					optarg);
				break;
			case 'o':
				if (NULL==(salida=fopen(optarg,"a")))
				{
					fprintf(stderr,
						"archivo salida \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr, "usando \"%s\" para salida\n",
					optarg);
				break;
			case '?':
			case 'h':
			default:
				usar(argv[0]);
				break;
		}
	}

	if (!entrada)
	{
		entrada = stdin;
		fprintf(stderr, "usando stdin para entrada\n");
	}

	if (!salida)
	{
		salida =stdout;
		fprintf(stderr, "usando stdout para salida\n");
	}

	fprintf(stderr, "Hace el trabajo aqui\n");

	fprintf(stderr,"Cerrando archivos\n");
	fclose(entrada);
	fflush(salida);
	fclose(salida);

	return 0;
}

void usar(char* cmd)
{
	fprintf(stderr, "uso: %s [-i entrada] [-o salida]\n", cmd);
	fprintf(stderr, "si no se informa -i, se usa stdin\n");
	fprintf(stderr, "si no se informa -o, se usa stdout\n");
	exit(EXIT_FAILURE);
}
Anuncios

Nuestro siguiente paso sera comenzar a definir los prototipos que declaramos, para ello agregaremos este bloque detras de la declaracion de la funcion usar:

int getNombre(FILE* entradaDesc, char* aCdn)
{
        static int numNombres = 0;
        int len;

        memset(aCdn, 0, max_cadena);

        if(stdin == entradaDesc)
                fprintf(stdout, "Nombre %d: ", numNombres+1);

        fgets(aCdn, max_cadena, entradaDesc);

        len = strlen(aCdn);

        if (len) numNombres++;

        return len;
}
Anuncios

Primero definiremos una variable de tipo static para tener en todo el programa y podes tener el total de nombres obtenidos, luego declaramos uno para el tamaño, ya veremos para que, tenemos un condicional donde verificamos si el argumento de entrada es igual a stdin, en caso de ser asi mostramos un mensaje en pantalla con el numero de nombre, despues por medio de fgets ingresaremos el nombre, en caso de no ser stdin lo tomara desde el origen, despues a len le asignaremos el resultado de aplicar la funcion strlen a la cadena almacenada en aCdn, si len tiene un valor procedemos a incrementar numNombres para finalmente devolver el valor en len, con esto comentado pasemos a buscar el siguiente bloque de codigo:

void putNombre(char* aCdn, FILE* salidaDesc)
{
        fputs(aCdn, salidaDesc);
        fputc('\n', salidaDesc);
}
Anuncios

Esta sera la definicion de putNombre donde tendremos la cadena o nombre a escribir y el que usaremos de salida, ya sea el stdout o el archivo, por medio de fputs lo escribiremos y por medio de fputc escribiremos el <newline>, con esto ya tenemos nuestros prototipos definidos, vamos a trabajar un poco en el main y para ello modificaremos esta linea:

fprintf(stderr, "Hace el trabajo aqui\n");
Anuncios

Por el siguiente segmento de codigo:

char buffer_nombres[max_cadena];

while(getNombre(entrada, buffer_nombres)>1)
	putNombre(buffer_nombres, salida);
Anuncios

Primero declaramos una variable que usaremos los distintos nombres que obtengamos del archivo o ingresemos, despues mediante un bucle while obtendremos los nombres del archivo o del stdin, y cada uno de ellos los almacenaremos en el archivo de salida o lo mostraremos en el stdout, utilizamos el mayor a uno para que en caso de pasar un caracter en blanco o Enter procede a salir del programa, con todo esto comentado pasemos a ver como es el codigo final de nuestro programa:

program.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/errno.h>

const int max_cadena=80;

void usar(char* cmd);
int getNombre(FILE* entradaDesc, char* aCdn);
void putNombre(char* aCdn, FILE* salidaDesc);

int main(int argc, char* argv[])
{
	int c;
	FILE* entrada = NULL;
	FILE* salida = NULL;

	while((c = getopt(argc, argv, "i:o:h")) != -1)
	{
		switch(c)
		{
			case 'i':
				if (NULL==(entrada=fopen(optarg,"r")))
				{
					fprintf(stderr,
						"archivo entrada \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr,"usando \"%s\" para entrada\n",
					optarg);
				break;
			case 'o':
				if (NULL==(salida=fopen(optarg,"a")))
				{
					fprintf(stderr,
						"archivo salida \"%s\": %s\n",
						optarg, strerror(errno));
					exit(EXIT_FAILURE);
				}
				fprintf(stderr, "usando \"%s\" para salida\n",
					optarg);
				break;
			case '?':
			case 'h':
			default:
				usar(argv[0]);
				break;
		}
	}

	if (!entrada)
	{
		entrada = stdin;
		fprintf(stderr, "usando stdin para entrada\n");
	}

	if (!salida)
	{
		salida =stdout;
		fprintf(stderr, "usando stdout para salida\n");
	}

	char buffer_nombres[max_cadena];


	while(getNombre(entrada, buffer_nombres)>1)
	{
		putNombre(buffer_nombres, salida);
	}

	fprintf(stderr,"Cerrando archivos\n");
	fclose(entrada);
	fflush(salida);
	fclose(salida);

	return 0;
}

void usar(char* cmd)
{
	fprintf(stderr, "uso: %s [-i entrada] [-o salida]\n", cmd);
	fprintf(stderr, "si no se informa -i, se usa stdin\n");
	fprintf(stderr, "si no se informa -o, se usa stdout\n");
	exit(EXIT_FAILURE);
}

int getNombre(FILE* entradaDesc, char* aCdn)
{
	static int numNombres = 0;
	int len;

	memset(aCdn, 0, max_cadena);

	if(stdin == entradaDesc)
		fprintf(stdout, "Nombre %d: ", numNombres+1);

	fgets(aCdn, max_cadena, entradaDesc);

	len = strlen(aCdn);
	if (len) numNombres++;

	return len;
}

void putNombre(char* aCdn, FILE* salidaDesc)
{
	fputs(aCdn, salidaDesc);
	fputc('\n', salidaDesc);
}
Anuncios

Con todo esto comentado vamos a proceder a probar como funciona nuestro codigo, para ello veamos el siguiente video

Anuncios

En el video podemos como primero llenamos un archivo de texto con algunos nombres, luego ejecutamos el programa para que tome los datos del archivo que llenamos recien y los copio en el archivo de salida, despues mostramos que se haya realizado y como siguiente paso fue volver a ejecutarlo pero ahora para que tome a stdin como ingreso, agregamos mas nombres y cuando finalizamos volvimos a chequear el archvo de salida y vemos los nuevos nombres, con esto ya tenemos un programa que nos permite copiar informacion de un archivo a otro asi como agregar mas por medio del stdin.

Anuncios

En resumen, hoy hemos visto como procesar archivos, ya sea desde tomar los datos desde un archivo y copiarlos en otro, hasta la posibilidad de poder agregar mas datos por medio de stdin, en este caso no solo hemos aplicado conocimientos visto en los ultimos posts sino otras cosas que hemos visto en otros posts a lo largo del curso pero en el proximo post veremos algo mas divertido sobre este programa, espero les haya sido de utilidad 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
pp258

Donación

Es para mantenimento del sitio, gracias!

$1.50