Anuncios

Bienvenidos sean a este post, hasta el post anterior hemos creado una solucion casi totalmente productiva pero con un solo inconveniente como es el tema de la ubicacion de los archivos, como no podemos estar modificando a cada rato nuestro codigo deberemos usar un archivo de configuracion.

Anuncios

Para este caso primero vamos a usar al proyecto Alumnos donde crearemos una nueva clase y la llamaremos Inifile.cs, esta la crearemos dentro de la carpeta Clases, pasemos a reemplazar el codigo generado por el siguiente:

Inifile.cs

using System;
using System.Collections.Generic;
using System.IO;

namespace Alumnos.Clases
{
    public class Inifile
    {
        private string _archivo;
        private string ComentLimit;
        private Dictionary<string,string> diccionario=new Dictionary<string, string>();
        public Inifile(string archivo, string comentLimit = ";")
        {
            ComentLimit = comentLimit;
            elarchivo = archivo;
        }

        public string elarchivo
        {
            get
            {
                return _archivo;
            }

            set
            {
                _archivo = null;
                if (File.Exists(value))
                {
                    _archivo = value;
                    using (StreamReader sr = File.OpenText(_archivo))
                    {
                        string linea, seccion = "", clave = "", clave2 = "", valor = "";
                        while ((linea = sr.ReadLine()) != null)
                        {
                            if (linea.Length == 0)
                                continue;

                            if (!String.IsNullOrEmpty(ComentLimit)
                                && linea.StartsWith(ComentLimit))
                                continue;

                            if (linea.StartsWith("[") && linea.Contains("]"))
                            {
                                int indice = linea.IndexOf(']');
                                seccion = linea.Substring(1, indice - 1).Trim();
                                // Console.WriteLine(seccion);
                            }
                            if (linea.Contains("="))
                            {
                                int indice = linea.IndexOf('=');
                                clave = linea.Substring(0, indice).Trim();
                                valor = linea.Substring(indice + 1).Trim();
                                if (valor.StartsWith("\"") && valor.EndsWith("\""))
                                {
                                    valor = valor.Substring(1, valor.Length - 2);
                                }
                            }

                            // Console.WriteLine(seccion + "->" + clave + "->" + valor);
                            if (seccion != "" && clave != "")
                            {
                                clave2 = seccion + "-" + clave;
                                diccionario.Add(clave2, valor);
                            }
                        }
                    }
                }
            }
        }

        public string mostrar(string seccion, string dato)
        {
            string clave = seccion + "-" + dato;
            return diccionario[clave];
        }
        
    }
}
Anuncios

En esta nueva clase primero definiremos las siguientes variables:

private string _archivo;
private string ComentLimit;
private Dictionary<string,string> diccionario=new Dictionary<string, string>();
Anuncios
Anuncios

En este caso primero crearemos una variable de tipo privado llamado _archivo, luego otra llamada ComentLimit, ambas de tipo string, la primera sera para manejar el nombre del archivo de configuracion, el segundo sera para definir que caracter usaremos de comentario, la siguiente linea sera para crear un diccionario (Dictionary) para almacenar los valores que obtendremos del archivo, de esto hablaremos en un rato, luego tendremos este constructor:

public Inifile(string archivo, string comentLimit = ";")
{
    ComentLimit = comentLimit;
    elarchivo = archivo;
}
Anuncios
Anuncios

En este caso le haremos que reciba dos datos pero uno sera opcional, el primero sera el nombre del archivo y lo almacena en archivo y el segundo sera para informar cual va a ser el simbolo de comentario, sino comentamos ninguno tomara de manera predeterminada el punto y coma, luego en el bloque asignara a elarchivo el valor que informamos en archivo y en ComentLimit el valor informado de comentLimit sino informamos ninguno pasara el predeterminado.

Anuncios

Despues usaremos a set y get para modificar los accesos a elarchivo, para ello usamos lo mismo que vimos en el post de getter and setter, donde declaramos la variable:

public string elarchivo
Anuncios

Luego usaremos un bloque de llaves donde primero definiremos a get el cual retornara el valor de _archivo, nuestra siguiente definicion sera la de set, primero setearemos a _archivo con el valor null luego usaremos un condicional que verifica si existe el archivo informado a elarchivo, en caso de ser cierto hara todo el resto de lo contrario deja a _archivo como null.

Anuncios

En el bloque del condicional lo primero que hacemos es setear _archivo con el valor de value, value es la propiedad que almacena el valor que le asignamos a la variable es propio del lenguaje y lo tenes a disposicion siempre, como siempre utilizamos a using para poder ejecutar el StreamReader para leer el archivo que informamos en _archivo, primero definiremos estas variables:

string linea, seccion = "", clave = "", clave2 = "", valor = "";
Anuncios

Estas las usaremos para almacenarnos distintos datos de nuestro archivo, primero usaremos el while que utilizamos habitualmente donde verifica que el valor almacenado en linea sea disitinto de null, el ReadLine lee la linea completa y la almacena en la variable del mismo nombre, una vez dentro del bloque encontraremos este condicional:

            	if (linea.Length == 0)
            	    continue;
Anuncios

Este bloque se encargara de verificar el tamaño de linea, si es igual a 0 procede a omitir la vuelta porque considera que es una linea vacia, veamos el siguiente condicional:

            	if (!String.IsNullOrEmpty(ComentLimit)
            	    && linea.StartsWith(ComentLimit))
            	    continue;
Anuncios

Este verifica primero que hayamos informado un caracter de comentario y con otra condicion donde verificamos si linea comienza con ese caracter todo con el operador logico AND (&&) si las dos son verdaderas considera que la linea esta comentada y procede a saltar esta vuelta del bucle, nuestro siguiente condicional:

            	if (linea.StartsWith("[") && linea.Contains("]"))
            	{
                	int indice = linea.IndexOf(']');
	                seccion = linea.Substring(1, indice - 1).Trim();	            		}
Anuncios
Anuncios

Primero verifica si comienza con un corchete ([) y luego verifica si en la misma contiene otro corchete (]) si se cumplen ambas condiciones, significa que es la etiqueta de la seccion de la configuracion y procedera a primero crear una variable donde almacenara la posicion del ultimo corchete para luego usar un SubString donde le diremos que empiece de la posicion 1 y que vaya hasta el valor de indice restandole uno, y por ultimo usaremos un Trim para eliminar cualquier espacio en blanco al principio o al final, todo esto lo almacenaremos en seccion, nuestro siguiente condicional es este:

     	        if (linea.Contains("="))
    	        {
        	        int indice = linea.IndexOf('=');
        	        clave = linea.Substring(0, indice).Trim();
        	        valor = linea.Substring(indice + 1).Trim();
        	        if (valor.StartsWith("\"") && valor.EndsWith("\""))
        	        {
        		    valor = valor.Substring(1, valor.Length - 2);
        	        }
    	        }
Anuncios
Anuncios

Este se encargara de buscar si existe un simbolo de igual (=) en caso de ser cierto quiere decir que aqui esta almacenado el valor con la referencia, para ello volveremos a usar otro indice para verificar en que posicion esta el igual, despues a clave la asignaremos el valor obtenido por la SubString que iniciara desde la primer posicion hasta el valor de indice, y con un Trim limpiaremos los espacios adelante y atras, luego asignaremos a valor el extracto que obtengamos del Substring pero esta vez no diremos una longitud para que lo haga hasta el final, por ultimo usaremos un condicional donde verificara si el comienzo y el final de valor posee comillas, en caso de ser cierto usa un Substring donde omite el primer caracter y le restamos dos para omitir el ultimo caracter y el anterior, con esto tenemos a clave y a valor, pasemos al ultimo condicional:

    	        if (seccion != "" && clave != "")
    	        {
    	            clave2 = seccion + "-" + clave;
    	            diccionario.Add(clave2, valor);
    	        }
Anuncios

Este verifica si seccion y clave son distintos de nada, en caso de ser verdadero procedemos a asignar a clave2 el valor de seccion concatenado con el valor de clave y en el medio un guion, con esto creado adicionaremos a clave2 como la clave de busqueda y a valor como el valor de la clave, pasemos al siguiente metodo:

        public string mostrar(string seccion, string dato)
        {
            string clave = seccion + "-" + dato;
            return diccionario[clave];
        }
Anuncios

En este caso tenemos un metodo para obtener el valor de diccionario, para ello le pediremos dos valores, seccion y dato, lo primero que haremos sera concatenarlo de la misma forma que lo hicimos antes, para luego por medio de un return devolveremos el valor almacenado en diccionario en base a la clave que generamos, con esto concluimos con la clase, para ponerlo en practica vamos a modificar a la clase Estudiantes de la siguiente manera:

Estudiantes.cs

using System;
using System.IO;

namespace Alumnos.Clases
{
    public class Estudiantes
    {

        Inifile configuracion = new Inifile("config.ini");

        string pathAlumnos;
        string pathExamenes;
        string pathNotas;

        public void ListarAlumnos()
        {
            pathAlumnos = configuracion.mostrar("rutas","alumnos");
            Console.WriteLine("Codigos de los alumnos: ");
            using (StreamReader sr = File.OpenText(pathAlumnos))
            {
                string linea;
                string[] s;
                while ((linea = sr.ReadLine()) != null)
                {
                    s = linea.Split(',');
                    Console.WriteLine(s[0] + " - " + s[2] + "," + s[1]);
                }
            }
            Console.Write("Presiona Enter para volver al menu");
            Console.ReadLine();
        }
        public void MostrarNotas()
        {
            string alumno;
            pathNotas = configuracion.mostrar("rutas", "notas");
            pathExamenes = configuracion.mostrar("rutas", "examenes");
            Console.Clear();
            Console.Write("Ingresa el ID del alumno: ");
            alumno = Console.ReadLine();
            using (StreamReader sr = File.OpenText(pathNotas))
            {
                float total = 0;
                int cuenta = 0;
                string examen = "";
                string linea,t;
                string[] s, u;
                while ((linea = sr.ReadLine()) != null)
                {
                    s = linea.Split(',');
                    if (s[1] == alumno.ToUpper())
                    {
                        using(StreamReader sr2 = File.OpenText(pathExamenes))
                        {
                            while((t = sr2.ReadLine())!=null)
                            {
                                u = t.Split(',');
                                if (u[0] == s[0])
                                    examen = u[1];
                            }
                        }
                        Console.WriteLine(s[1] + "\t" + examen + "\t" + s[2]);
                        total += float.Parse(s[2]);
                        cuenta++;
                    }
                }
                Console.WriteLine("Tu promedio es: " + (total/cuenta));
            }
            Console.Write("Presiona Enter para volver al menu");
            Console.ReadLine();
        }
    }
}
Anuncios

La primera modificacion sera la siguiente:

        Inifile configuracion = new Inifile("config.ini");

        string pathAlumnos;
        string pathExamenes;
        string pathNotas;
Anuncios

Primero crearemos el objeto de la clase que comentamos antes y le pasamos el archivo config.ini, nuestro siguiente paso sera declarar las tres variables que usaremos para los paths, nuestras siguientes modificaciones seran en los metodos, donde usaremos el metodo mostrar, primero veamos el metodo ListarAlumnos:

        public void ListarAlumnos()
        {
            pathAlumnos = configuracion.mostrar("rutas","alumnos");
Anuncios

En este caso la primera linea sera para definir a pathAlumnos donde usaremos al metodo mostrar y le pasaremos dos valores (rutas y alumnos), nuestro siguiente metodo sera modificado de la siguiente manera:

        public void MostrarNotas()
        {
            string alumno;
            pathNotas = configuracion.mostrar("rutas", "notas");
            pathExamenes = configuracion.mostrar("rutas", "examenes");
Anuncios

En este caso volvemos a definir las variables para los paths pero vean como usamos la misma seccion (rutas) pero variamos los datos (notas y examenes) para traer las rutas que correspondan, con estas modificaciones realizadas podemos compilar pero nos dara un error, esto es debido a que todavia no existe el archivo config.ini.

Anuncios

Para probar nuestra nueva modificacion deberemos crear un archivo de texto simple, puede ser con el notepad o con el boton derecho -> nuevo -> documento de texto, una vez hecho lo deben llamar config.ini, para que coinicida con el del codigo, y debe estar al lado de nuestro ejecutable:

config.ini

; Este es el sector de desarrollo
[rutas]

alumnos="..\..\..\alumnos.txt"
examenes="..\..\..\examenes.txt"
notas="..\..\..\notas.txt"

; Este sera el sector de produccion
;[rutas]

;alumnos="c:\universidad\alumnos.txt"
;examenes="c:\universidad\examenes.txt"
;notas="c:\universidad\notas.txt"
Anuncios
Anuncios

Como pueden ver podemos tener dos configuraciones en un mismo archivo, una parte para cuando necesitamos corregirlo o trabajarlo (desarrollo) y otra donde estara en produccion, podemos hacer comentarios y con simplemente comentar o no una linea podemos desactivar o activar la misma, otro detalle es que nosotros podemos agregar otras configuraciones y distinguirlas por medio de un titulo que lo pondremos entre corchetes ([]) y siempre debajo usaremos el identificador a la izquierda del igual y el valor a la derecha, esta es una forma arcaica pero mas simple que otras para tener una configuracion para nuestras aplicaciones, es decir que a partir de ahora simplemente con modificar un archivo de texto podemos trabajar con distintas ubicaciones de archivos y no tener que modificar nuestro codigo cada vez que debamos hacer un cambio.

Vamos a compilarlo y probarlo mediante el siguiente video tambien veremos como se aplica en produccion

Anuncios

En el video podemos ver como lo pudimos probar en desarrollo primero, luego como lo pasamos a produccion y como modificamos el archivo .ini para poder acceder a los archivos de produccion en lugar de los ubicados en desarrollo.

Anuncios

En resumen, hoy hemos visto como crear una clase que nos permite recuperar datos de configuracion desde un archivo, como podemos tener distintas secciones con sus respectivos datos, las facilidades que nos provee y como nos puede expandir para otras posibilidades, espero les haya gustado 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 $