10 diciembre 2006

Visual Basic .NET - Dejemos todo al azar...

¿Alguna vez has escuchado alguna frase relacionada a los "azares del destino"? No sé que tan cierto es eso que el destino sucede al azar (algunos están en desacuerdo con esta idea, como lo está Amado Nervo en su poema "Vida nada te debo"), pero los programadores no creen en que hay tanto azar en las cosas porque, aunque es posible (y muy útil) hacer archivos que se puedan accesar de manera aleatoria, se obtiene solamente lo que se ha grabado en ellas.

A lo mejor ya los hice bolas con los poemas (lo mencioné como simple cultura general) y los programadores. La idea es que puedo crear archivos por medio de los archivos de programación (aunque ahorita me interesan los que se pueden hacer en Microsoft Visual Basic .net) que pueden ser accesados de manera aleatoria. Esto del acceso aleatorio es una manera rimbombante de decir que podemos accesar cualquier parte del archivo que se nos pegue la gana en el momento en que se nos pegue la gana. Como habrás notado si leíste algunos de mis posts anteriores, este tipo de archivo difiere de los archivos secuenciales en que éstos últimos solamente pueden ser leídos desde el principio hasta el final, o sea, no es permitido saltar a cualquier parte del archivo y agarrarnos leyendo. No es que un tipo de archivo sea mejor que otro: cada uno tiene sus propios usos.

Como no todo es al azar, los programadores decidieron ponerle cierta estructura a las cosas para que no todo fuera tan alocado. Gracias a estas estructuras, podemos usar un archivo de acceso aleatorio como una tabla de una base de datos.

Para ilustrar como funciona esto, hice una pequeña aplicación que le podría servir a la biblioteca personal de alguien. Esta es la imágen del programa en funcionamiento:



La aplicacion usa las cajas de texto para llenarlos de valores y guardar el registro o para mostrar los datos de un libro leído. Todo esto funciona por medio de los botones, pero solo para farolear y aumentar mi ego y autoestima, decidí también tener un menú contextual que sirva para hacer lo mismo. Así es el diseño del menú:



Ahora, vámonos al código. Pero, como diría Jack el destripador, vámonos por partes. Para empezar, esta es la estructura que voy a usar para guardar los datos de los libros y algunas variables globales que me van a ser útiles. Todo esto va a dentro del Public Class Form1.



No voy a redundar con una explicación acera de cómo se hacen las estructuras porque ya escribí acerca de ellos aquí. De las variables, solo quiero aclarar lo que guardar. Librote es la instancia de la clase Libro que voy a usar, NombreArch es una cadena que tiene el nombre del archivo (toda la ruta completa) y NoReg guarda el número de registros que están almacenados en el archivo.

Todo esto se inicializa en el Form1_Load como se ve en esta figura. Lo primero que hace es asignarle el nombre Biblioteca.tvr a la cadena NombreArch (fíjate que al usar el Directory.GetCurrentDirectory, estoy diciendo que ese archivo va a estar en la misma carpeta donde se encuentra el archivo .EXE de esta aplicación). Luego consigo un número de archivo disponible (con el FreeFile()) y lo abro. Se te fijas, el uso de FileOpen() cambia un poco en relación a su uso con los archivos secuenciales. Como en el código no se ve toda la instrucción, más adelante (después de este código). Luego cuento el número de registros y guardo en dato en NoReg. Para hacer esto, comienzo a leer todos los registros usando la instrucción FileGet(), uno a uno, e ir acumulando en NoReg cuantas veces he leído hasta llegar al final del archivo (uso EOF() para saber si ya llegué al final). Y no hay que olvidar cerrar el archivo al final. Esto lo hago con FileClose().

En este mismo bloque de código, puse lo que tiene el Form1_MouseDown que se va a encargar de mostrar el menú contextual chiroliro que puse.



Ahora sí: la instrucción FileOpen() completo :

FileOpen(NoArch,NombreArch,OpenMode.Random,OpenAccess.ReadWrite,OpenShare.Default,Len(Librote))


Arriba expliqué lo que contiene NoArch y NombreArch. OpenMode.Random indica que vamos a usar un archivo de acceso aleatorio, OpenAccess.ReadWrite indica que vamos a poder leer datos del archivo y escribir datos a él. OpenShare.Default maneja toda la movida que pasa cuando varias personas quieren abrir el archivo al mismo tiempo. Se puede bloquear de escritura, lectura, etc. Con el Default le estoy dejando la bronca a VBasic .NET y le digo que ahi le encargo la bronca, que lo resuelva como mejor le parezca. Al final, uso la función Len() para que me devuelva el tamaño en bytes de la estructura, o sea, el tipo de dato de la variable Librote (o sea, una instancia de la estructura Libro). Esto es muy necesario para poder manejar las estructuras en el archivo. Si no le digo cuanto mide cada registro, es imposible que lo pueda hallar a la primera cuando le digo "quiero el registro 1355 y lo quiero rapidito". En el archivo, mide le número de bytes que se tiene que "saltar" para leer ese registro, o sea, el tamaño de Librote * 1355. ¿Entendido? ¡Adelante pues con lo que sigue!

Para cada acción que puede realizar el usuario tengo dos eventos donde lo puede hacer ya sea puchurrando (nuevo verbo, jeje) el botón o usando el menú contextual farol. Por esta razón, hice funciones que hicieran estas tareas vanas y rutinarias. Aquí está el ejemplo del código de los eventos que pone en blanco a todas las cajas de texto de la ventana y luego los eventos que guardan la información que está en la pantalla. Está tan fácil, que ni necesita explicadera.


El código que limpia la ventana (muy original, se llama LimpiaVentana) no tiene ninguna ciencia. Limpia la ventana (o sea, quita cualquier resto de texto que haya quedado por allí... pensándolo bien, nunca hay texto por allí... en fin, esa es la idea) e inicializa la estructura en ceros. Después hay una función AsignaLibro que copia los valores que hay en Librote a las cajas de texto de la ventana.



Ahora sí, algo más interesante. A continuación está la función GuardaLibro que se encarga de meterlo en su lugar quesque-aleatorio en el archivo. Hace lo mismo que hace Form1_Load al principio: encuentra un número de archivo que se puede usar y abre el archivo. Después le asigna a Librote los valores que hay en los Textboxes y al final le agrega uno al número total de registros para poder poner allí, en esa posición del archivo (en este caso, al final) el contenido de Librote. Una vez terminado, escribo el registro usando la función FilePut(), lo cierro y uso la función que limpia la ventana.



Sería inútil en este mundo guardar cosas si no los voy a usar. Bueno, eso pasa en nuestras casas cuando vamos acumulando tilichero, pero en las computadoras intentamos reducir el tilichero al máximo. Depsués de divagar en tiliches, intento decir que es muy importante consultar los datos que almacenamos porque si no los consultamos, mejor dedíquense a otra cosa y no se esfuercen en hacer programas. Pero como queremos hacer algo útil, ahi va la manera de accesar los datos que hemos guardado.

Hay 3 botones (y 3 elementos del menú farol) que hacen diferentes consultas. Dos de ellas son muy similares, el que busca por el título y el que busca por el ISBN (nada que ver con el INSEN). Los dos hacen prácticamente lo mismo: van desde el principio del archivo leyendo registros y comparándolos con el título o ISBN dado en un InputBox chafa que puse allí (mi idea es la de ejemplificar, no la de hecer una aplicación 100% terminada y fresón). El funcionamiento es también muy similar a lo que expliqué en el Form1_Load(), así que escribo aquí el código de la función BuscaISBN.


La otra manera de buscar sería la de accesar de forma directa el registro que quiero y leer los datos, o sea, la función quesque aleatoria del archivo. Para hacer esto, hay de dos sopas: usar la función FileGet() con el último parámetro que indica el número de registro que quier leer o usar la función Seek() para moverse al lugar en el archivo donde está ese registro y luego usar el FileGet() sin el parámetro del número del registro. Como es un mero ejemplo, lo hice de las dos maneras en la función BuscaReg, quien es la función encargada de buscar un libro por número de registro.


Parece que es todo. Espero que esto les sea útil. Bike.

06 diciembre 2006

SQL: SELECT parte 9 - Cambiando nombres

Si eres una persona como yo, es común que se te olvide los nombres de las personas que te rodean. O incluso he da por cambiarles el nombre a la gente. Parece ser que es un mal común a los que usan SQL porque incluyen una pequeña ayuda para que puedas cambiarle los nombres a los campos de una tabla cuando lo estás consultando. No hace ningún cambio al diseño de la tabla, solo cambia el nombre del campo en tu consulta.

¿Y cómo funciona esta maravilla del mundo moderno? Fácil, solo tienes que conocer el AS (nótese de antemano que solo tiene una S, no se confundan...). El AS se pone al final de un campo seguido por el nuevo nombre que se le dará a ese campo. Solamente lo cambiará el nombre del campo en la consulta por lo que no altera el diseño de las tablas.

Por ejemplo, supongamos que me da flojera mostrar un campo cuyo nombre es muy largo. Se vería así:

SELECT apellido_paterno_del_empleado AS Paterno FROM Clientes ORDER BY Sexo, Edad DESC, Salario

¡Y ya está! Simplemente simplifica la consulta por parte del usuario. No parece gran ayuda, pero considera el caso en que están mandando instrucciones SQL a tu manejador de bases de datos (o DBMS) por medio de algún lenguaje extraño de programación. Estar escribiendo ese nombresototote de campo a cada rato puede cansar y enfadar...

05 diciembre 2006

Visual Basic .NET: Estructurando ideas

Tengo un problema más o menos grave: tengo una pésima memoria (bueno, casi carezco de ella). Entonces, cuando salgo de viaje, pongo todas las cosas que puedo necesitar durante el en una sola mochila. De esa manera, son menos las cosas que tengo que andar buscando por todos lados y con saber donde está mi mochila, ya sé donde están todas mis cosas (el detalle también es que si se me olvida la mochila, ya bailé con Bertha las calmadas...). Podría tener mis cosas repartidas en diferentes mochilas, bolsas, etc., sin embargo me simplifico la vida si tengo todo junto.

A lo mejor este es un mal de los programadores porque en muchos lenguajes existe la manera de crear estructuras de datos, las cuales son entidades que son compuestas por varias variables, pero en un solo bloque. Esto facilita el manejo de datos en casos que se tiene información relacionada, por ejemplo, si quiero almacenar los datos de un amante, en lugar de tener que guardar sus datos en diferentes lugares (por ejemplo, arreglos de nombre, apellidos, domicilio, teléfono, IMeil, etc. o archivos diferentes donde un archivo guarda un dato o campo). Es por esto que se usan tablas en las bases de datos: cada registro tiene todos los datos que tienen que ver entre sí.

Espero que esta analogía resalte la importancia que tiene el uso de estructuras. La idea es la misma en todos los lenguajes que los soportan, lo único que cambia es la manera de definirlos. En VBasic .NET se definen de la siguiente manera:

Structure nombre
declaración de las variables
End Structure

Por ejemplo:

Structure Amante
Dim Nombre as String
Dim Apellidos as String
Dim IMeil as String
Dim Tel as String
Dim Edad As Integer
Dim Salario As Decimal
End Structure

¿Está bien esto? Casi. A diferencia de otros lenguajes (como el C o C++), VBasic tiene un tipo String que puede contener cadenas de cualquier longitud. Sin embargo, para nuestros fines particulares, tenemos que limitar el número de puede almacenar cada una. Para esto, escribimos algo como lo siguiente:


¡Ahora si! Hasta aquí todo bien pero, ¿cómo se usan? Más adelante (otro día) escribiré como usar las estructuras para crear archivos de acceso aleatorio, sin embargo, ahorita voy a escribir un poco de código que asigne datos a una variable de tipo Amante.

... (adentro de cualquier función) ...
Dim Persona As Amante
Persona.Nombre="Lisa"
Persona.Apellidos="Simpson"
With Persona
.Edad=9
.Salario=1245.33
.Tel="(33) 3435-3444".IMeil=lisa_simpson@hotmail.com
End With


Ahora si. Se usa el punto para separar el nombre de la variable de tipo Amante (Persona) de la variable a la que quiero hacer acceso. También puedo usar el With para ahorrarme la flojera de escribir tanto el nombre del objeto tantas veces.

En la próxima usaré las estructuras para hacer archivos de acceso aleatorio para guardar, buscar y leer datos, al estilo de una base de datos. ¡Hasta la próxima!

03 diciembre 2006

Dreamweaver: Marcos (vulgarmente llamados "Frames")

Los marcos son muy útiles a la hora de diseñar páginas güev (o sea, la versión mexicana de la "web", jeje) de todo tipo. Básicamente es una zona de la página que contiene otra página y su contenido es independiente de los otros elementos en la ventana del navegador. Podemos hacer páginas web que definan un conjunto de marcos y jugar entre ellos con ligas y muchas otras cosas divertidas.

Antes de empezar con todo el choro mareador que traigo, quiero que recuerdes que los marcos no son la solución definitiva para todo tipo de formatos chidos en páginas web. De hecho, pese a que antes eran muy usados, han comenzado a caer en desuso. Pero yo los explico aquí y ya es bronca tuya si los usas o no o como los uses o porque los usas o donde los usas o con quien los usas... en fin, ahi va.

Para este experimento, empecé haciendo una nueva página HTML. El archivo lo llamé "marcos.html". Lo voy a ir transformando en un archivo que defina 3 marcos: uno arriba uno estrecho a la izquierda y otro de todo el espacio que queda.

Para insertar un marco, pongo el cursor (o sea la rayita vertical que parpadea, no la del mouse) en la página o marco donde deseo añadir uno. Una vez situado, posicionado y listo para la acción, voy en los menús Insert>HTML>Frames (o Insertar>HTML>Marcos si estás usando la versión en español). Allí hay varias opciones de marcos a insertar. Yo comencé insertando un marco en la parte superior de la ventana (o sea la opción top). Al darle eso, me apareció la siguiente ventana que me pide que le de un nombre al marco. Es necesario, nuestro deber y salvación ponerle un nombre en todo lugar, bueno en todo marco (eso se escuchó medio hereje... sorry, solo era una bromita) porque si no tiene nombre, ¿dónde sé que se va a poner en cada marco? Imagínate que vas a una pachanga y conoces a 3 chicas (o chicos) super guapas(os). Si no sabes el nombre de cada uno, te vas a meter en broncas porque no vas a saber como llamarle a cada uno. Si dices "mi amor", sepa cuál va a voltear (si es que alguno voltea). Y como esto, mil otras broncas.

Ya divagué bastante. Regresando a la materia, despues de mi lapsus brutus, en la ventana que aparece (Frame Tag Accessibility Attributes) le tengo que decir cuál ventana (en mi caso, elegí topFrame, o sea el marco de arriba arribototota) y le puse el nombre MarcoSuperior (uy, que original...). Así se ve desde lejos, en la lontananza:


Una vez que le piqué al Ok, mi página y la barra de propiedades (que cambia según lo que tengo seleccionado) se ven así:


En mi página se ve una raya que divide verticalmente a la página en 2. Una vez hecho esto, voy a agregar un marco en el lado izquierdo, abajo del marco superior. Para esto, le doy click al marco inferior (para posicionar allí el cursor) y voy a Insert>HTML>Frames>Left. Ahora la ventana que me pide el nombre tiene 3 opciones: ponerle nombre al topFrame (que ya se llama MarcoSuperior), al leftFrame (el de la izquierda) y al mainFrame (lo que queda). Al leftFrame le puse como nombre "MarcoIzquierdo" y al mainFrame lo nombré "MarcoDerecho" (bueno, no soy muy original para nombrar marcos...). Ahora mi ventana se ve así:


Ahora, si son muy observadores, verán que en la pestaña que indica la ventana en que estoy trabajando (esquina superior izquierda de la ventana) dice marcos.html* (el * quiere decir que no lo he guardado desde la última modificación). Pero si pongo mi cursor en el marco superior o izquierdo, cambia de nombre. Se debe a que estoy creando un documento que tiene marcos y cada marco es independiente de los otros, tiene un archivo HTML diferente al de los demás. Por lo tanto, nuestro marcos.html ha quedado relegado al marco "MarcoDerecho".

Ahora solo resta ponerle contenido a los marcos (es decir, crear los archivos HTML de cada marco). Para esto, hago lo mismo en cada marco que haría en cualquier página (inserto imágenes, tablas, escribo texto, etc.). Sin embargo, al final cuando quiero guardar todo, sucede algo inesperado: de pronto quiere guardar un tal UntitledFrameset-2.html (que yo guardé como "defineframes.html"), un UntitledFrame-3.html (que yo le puse "izq.html") y UntitledFrame-4.html (que yo puse "arriba.html") y marcos.html. Conste que los nombres pueden variar un poco.

Ahora voy a "ligar" entre los marcos. Si se recuerdan (y si no se recuerdan, se las recuerdo, perdón, les recuerdo el concepto) cuando especifico un vínculo para un texto o imágen, hay una propiedad llamada Target que me permite poner donde quiero que se abra la liga. Ahora, trabajando en defineframes.html, aparece en el combobox Target las opciones mainFrame, leftFrame y topFrame, como podrás ver en la siguiente imagen. De esta manera puedes definir en que marco quieres que aparezca la página que quieres "ligar".



Creo que con eso tienen para seguir experimentando. ¡Hasta la próxima!

02 diciembre 2006

Generando archivos secuenciales con VBasic .NET y 2005

Pese a lo super modernos que nos hemos vuelto con el almacenamiento de datos, ya sea con ADO, ODBC, Oracle, Informix, SQL Server y hasta access, uno de los archivos más usados por los programas son los archivos de texto.

¿Archivos de texto? te preguntarás. ¿Qué no son ese tipo de archivos que usan los nacos que son tan tercermundistas que no pueden usar ni siquiera el Access que es casi gratuito? Eso creen algunos. Sin embargo, saber usar archivos secuenciales es escencial para poder hacer programas que verdaderamente valgan la pena.

¿Aún crees que son poco usados? Pues la mayor parte de los programas que requieren valores para configurarlos los guardan en archivos de texto (generalmente con extensiones INI o algo por el estilo).

Pero ahora le pregunta es, ¿cómo los programo? ¿Qué tengo que hacer? Precisamente en eso estaba pensando el otro día en una de mis meditaciones matutinas, así que se me ocurrió hacer un programita que generara y leyera archivos de texto secuenciales.

Aquí está la ventana en el modo de diseño. Consta de 5 Textboxes y tres opciones de un MenuStrip:



La opción de salir es muy clara. La idea es que cuando el usuario seleccione la opción Salir, el programa finalice. Por eso su código es tan simple (un simple End) que ni le doy más importancia.

Las otras opciones del menú principal son más interesantes. Del menú Generar muestra 2 maneras en que se pueden generar archivos de texto secuenciales: con o sin streams (los streams son objetios que nos permiten realizar funciones de entrada y salida. Estos son básicos con le manejo de archivos en C++ y como el VBasic .net se parece cada vez más al C++, 'pos ahi sabrás...). Lo que van a hacer estas funciones es grabar el texto de las 4 textboxes al archivo secuencial. LE puse texto por default, pero se puede cambiar por el usuario. De igual manera, el menú Leer consta con las mismas opciones, solo que en este caso son dos diferentes maneras de leer datos de un archivo de texto secuencial y arroja lo leído a la caja de texto grandota, el Textbox5. Así se ve el diseño de los menús:


Ahora sí, como dijo el dermatólogo, vámonos directo al grano: vamos viendo el código. Antes que nada, antes incluso del Public Class Form1, hay que escribir la instrucción Imports System.IO, el cual nos da acceso a las funciones de acceso a los archivos que vamos a usar más adelante.

Después de esto, la clase Form1 tiene 5 funciones: la NormalToolStripMenuItem_Click que se ejecuta cuando selecciona la opción de generar el archivo de texto de manera "normalita" (más adelanto explico el código de éste y las demás funciones), la ConStreamsToolStripMenuItem_Click que genera el archivo usando streams. Luego siguen las funciones que leen del archivo de texto sin y con streams (de hecho, se llaman casi igual que las funciones anteriores. Cuando esto sucede, VBasic le agrega un número al final como podrás observar).


Al hablar de la manera "normal" de escribir archivos, todo el acceso al archivo se hace mediante un número (un entero del 1 en adelante). Para esto resulta muy útil la función FreeFile() el cual nos devuelve el siguiente número disponible. Luego usé la función InputBox para pedir el nombre del archivo. Después de esto, la función FileOpen() me permite abrirlo. Los parámetros son sencillos: primero va el número que va a identificar al archivo, luego el nombre del archivo y después van los parámetros que indican el acceso. En este caso, como quiero escribir, le digo que el modo de apertura es de salida, o sea que vamos a escribir en él (OpenMode.Output) y que el modo de acceso, o sea cómo voy a acceder al archivo, va a ser de escritura (OpenAccess.Write) . Después uso la función WriteLine para escribir cada caja de texto al archivo. Sólo le tengo que dar el número del archivo y la cadena que quiero que escriba. Y al final de todo el rollo, ya que hice todo lo que quise con el archivo y no quiero usarlo más, le digo que cierre el archivo usando la función FileClose. Aquí está todo junto:



Esa es una manera de escribir, pero los chicos que están más en la onda de todo lo relacionado y orientado hacia los objetos prefieren usar streams. En este caso, se va a usar un objeto de tipo StreamWriter que al inicializarlo (con la instrucción New) abre el archivo para escritura (ese archivo se lo dí como parámetro). Después uso el método WriteLine del objeto StreamWriter para escribir todos los renglones. La única diferencia con el método "normal" es que no se necesita el número de archivo ya que este objeto "es" el archivo. Y al final, para cerrarlo todo, uso el método Close para terminar la escribidera.


¿Y qué método es mejor? ¿Con o sin streams? No hay mejores ni peores, solo maneras diferentes de hacer lo mismo. Yo te los comparto para que uses el que se te pegue la gana (suponiendo que se te pegó la gana programar, claro está...).

Ahora toca escribir. De la manera "normal" procedo casi igual que para escribir el archivo, solo que ahora uso los parámetros OpenMode.Input para decirle que el archivo va a dar entrada a datos y el OpenAccess.Read para leer de él. Además, en lugar de usar el WriteLine para leer, uso la función LineInput para leer una línea completa del texto y lo hago dentro de un ciclo (así me aseguro que va todo). Al final, igual que el metodo "normal" anterior, le digo FileClose para cerrar todo el changarro.


Así como leer de manera "normal" es casi igual que escribir de forma "normal", el uso de streams para leer es muy semejante al que se usó para escribir. Solo que ahora el objeto se llama StreamReader y estoy usando una función muy chida para leer todos los datos de un solo jalón: el tremendo ReadToEnd. Existe el LineInput, pero si teniendo algo "más mejor" como dirían en mi pueblo, lo usamos. Este es el código:


Con esto termino, con esto acabo. Presenté aquí dos maneras simples de escribir y leer datos a/desde un archivo secuencial de texto. Ahora faltaría hablar de archivos de acceso aleatorio, pero por lo pronto, ahi muere.
Related Posts Plugin for WordPress, Blogger...