Curso Básico de Programación
en Visual Basic

Entrega Doce: 10/Ene/98.
por Guillermo "guille" Som

Desde aquí puedes enlazar con las entregas anteriores.
La Primera, la Segunda, la Tercera, la Cuarta, la Quinta, la Quinta++, la Sexta, la Séptima, la Octava, la Novena, la Décima, la Undécima

 

Antes de empezar, recordarte que ya están las soluciones de la décima entrega. Te recomiendo que las veas y "las estudies", ya que tiene "truco"... y sería conveniente que te enteraras bien del porqué... Échale un vistazo y verás porqué te lo digo.

Ya vamos al tema de esta entrega... la número doce, (duodécima), es que es un lió esto de los números ordinales, así que usaré números normalitos, que todos los entendemos mejor...

Con esta entrega, empiezo la serie de manejo de datos almacenados en disco. Así que presta atención a esta y las siguientes entregas, para que esto del manejo de la información almacenada en disco te sea fácil de usar.

Además de las bases de datos, que también veremos en este curso básico... o en las secuelas que pueda tener... existe una forma de almacenar los datos que nuestra aplicación pueda manejar. Porque de qué serviría hacer, por ejemplo, un programa tipo editor de textos si no pudiésemos almacenar lo que se ha escrito...
No, aún no te voy a explicar cómo hacer un editor de textos, antes hay que ver algunas cosillas más, pero todo llega en esta vida, así que no desesperes...

El Basic maneja tres tipos de ficheros: secuenciales, aleatorios y binarios.

Cada uno tiene una serie de características en la forma de acceder a los datos.
El más básico y también el más empleado, es el secuencial; con este tipo de fichero, los datos se almacenan y recuperan de forma secuencial, es decir: un dato después de otro...
El inconveniente que tiene esta forma de almacenar los datos, es que para recuperar lo que esté en la décima posición, tenemos que leer los nueve anteriores...

Si tenemos que guardar, por ejemplo, el contenido de un array de strings, lo normal es que lo hagamos secuencialmente, es decir primero el contenido de la primera variable del array, después la segunda, tercera, etc., hasta llegar a la última.
Para recuperar estos datos, actuaríamos de igual forma, pero asignando al array los datos leídos del disco. Recuerda que para asignar una posición N, antes tendremos que leer las N-1 posiciones anteriores.
La ventaja de esta forma de almacenar los datos, es que la longitud de las cadenas, por ejemplo pueden ser variables... esto, ahora te parecerá una cosa normal, pero lo entenderás cuando veamos los otros tipos de accesos.
También permite que puedas almacenar distintos tipos de datos... no te preocupes, ya sabes que en estas entregas todo está "demostrado"... más o menos, ya que la teoría está bien para los teóricos, pero para los torpes como yo... lo mejor es la práctica... no es que quiera llamarte torpe... pero, así me siento menos solo... jé, jé.

El inconveniente es, como ya he repetido, que para acceder a un dato en concreto, se deben "leer" todos los anteriores.
Esta inconveniencia del acceso secuencial se arregla usando el acceso aleatorio. Con este tipo de acceso, puedes leer del fichero el dato almacenado en cualquier posición, sin tener que leer primero todos los anteriores... Pero, no todo es perfecto... también tiene un "pequeño" inconveniente... que los datos guardados en un fichero aleatorio deben ocupar el mismo espacio, o sea que sean de la misma longitud... Si guardas cadenas de caracteres, todas ocuparán el mismo espacio en el disco, aunque unas tengan más caracteres "válidos" que otras... También se pueden mezclar números y cadenas de caracteres... pero eso tiene también sus "inconvenientes" o mejor dicho su "truco" para poder usarlo sin armar un KAOS...
Ya que estamos con los distintos tipos de acceso, te diré así por encima de que va el tipo Binario, éste es un poco especial y permite leer la información almacenada de la forma que queramos, todo dependerá de la longitud de la variable que usemos para acceder al fichero... todo estas cosas quedarán explicadas y aclaradas en esta o en próximas entregas...

Bien, ya sabes que tipos de ficheros puedes manejar con el Visual Basic, ahora vamos a ver como hacerlo, por supuesto, con las instrucciones correspondientes para poder hacerlo, ya que de eso se trata... o es que ¿esperabas poder acceder a la información de los ficheros sin usar instrucciones del VB?

Cada vez que quieras abrir un fichero, tienes que usar un número de "canal" por el que VB nos suministrará la información, este canal. El canal se indica por medio de un número de 1 a 255. Gracias a este número, el Basic se comunica con el sistema operativo para acceder a los datos. El Basic nos facilita la tarea de conseguir ese número, con idea de que no usemos una línea que esté en uso... La instrucción, en realidad es una función, para conseguir un número de canal libre, es: Freefile. Esta función devuelve un número entero, el cual se almacenará en una variable y así podremos usarlo para el manejo de los datos almacenados.

NumFic = Freefile

Una vez que conozcamos un canal por el que poder acceder, tendremos que abrirlo:
Open "Prueba.txt" For Output As NumFic
Con esta línea, abrimos el fichero Prueba.txt de forma secuencial para poder escribir en él.
Una vez que tenemos una "vía" de comunicación, podremos escribir información usando una versión un poco maquillada de la instrucción Print... El maquillaje es el número de canal con el que podemos acceder al fichero:
Print #NumFic, "Lo que sea"
#NumFic es el número de fichero (o canal) por el que accedemos al fichero abierto y después de ese número, usamos una coma y a continuación lo que queremos guardar en el fichero.
Cuando hayamos acabado de guardar cosas, tendremos que cerrar el fichero que hemos abierto, para poder liberar ese canal abierto y así poder usarlo en otra ocasión, esto se consigue con el comando Close:
Close NumFic

Es importante esto de cerrar el fichero abierto, ya que en ese momento es cuando el Basic guarda la información que aún tiene "temporalmente" almacenada en una memoria intermedia que usa para que el acceso a datos sea, al menos en teoría, más rápido. A esta memoria intermedia se le llama "buffer". El VB la usa para ir guardando la información que vamos a grabar físicamente en el disco, antes de grabarla, la guarda ahí y cuando está llena, la escribe en el disco y la libera, esto se consigue con el close, para asegurarnos que todo lo que tenga que estar guardado, realmente lo esté. El valor de este búfer para los ficheros secuenciales y aleatorios puede ser de 32767 bytes como máximo, antes con el Basic del DOS el valor por defecto era de 128 bytes y el máximo de 255 caracteres, pero esto hace tiempo que cambió y ahora incluso, (al menos en el acceso de 32 bits), aunque en la ayuda no lo indique así, puede ser mayor que todo eso... Ya tendremos ocasión de comprobarlo.

Todo esto está muy bien, pero si quieres especificar esa longitud... ¿cómo y/o dónde se especifica?
Ahora sabrás cómo y dónde. Para ello vamos a ver cómo se usa al completo la orden OPEN y sus posibilidades de uso.

Open RutaAcceso [For Modo] [Access acceso] [tipo de bloqueo] As [#]númerofichero [Len=longitudregistro]

Lo que está entre corchetes son parámetros opcionales.
Fíjate en el detalle que FOR Modo está entre corchetes, esto significa que si no se especifica el modo, el Visual Basic entiende que quieres acceder de forma aleatoria. La explicación de cada uno de estos parámetros los tienes en la ayuda, así que si no quieres esperar a que los explique todos, vete a la ayuda y le echas un vistazo.
Yo empezaré a explicarte lo que ahora necesitas saber y poco a poco iremos viendo las distintas posibilidades... Pero si no quieres esperar... ya sabes... echa mano del F1 y accede a la explicación de la ayuda o del manual...

Vamos a ver lo que nos interesa de esta instrucción:

RutaAcceso   El path completo, o a medias, de dónde queremos que se almacene el fichero o el lugar en el que está almacenado.
Por ejemplo: C:\Datos\Un directorio\Prueba.txt
.\Algo\Prueba.txt, siempre que en el directorio actual haya un directorio que se llame "Algo"
o simplemente Prueba.txt (esto le indicará que estará en el directorio actual)
Modo    
  • Output, para ficheros de salida, es decir para guardar los datos.
    Si el fichero existe, lo borrará (sobrescribirá) y si no existe, lo creará.
  • Input, para leer los datos de un fichero ya existente.
    Append, como el Output, pero añadiendo la información al final del fichero, si este ya existe.
  • Random, para acceso aleatorio.
  • Binary, para acceso binario.

 

As NúmeroFichero   Aquí se indica el número de fichero (canal) por el que accederemos a la información.
El signo de número (#) es opcional. Y NúmeroFichero, puede ser una variable o una constante.

 

Las otras opciones ya las veremos, ahora nos centraremos en las cosas que son más fáciles, siempre hay tiempo para complicarse la vida, así que nos la complicaremos más adelante, cuando ya tengamos un poco de idea de todo este follón...

RutaAcceso, a estas alturas deberías saber de que va todo esto del PATH, pero si no lo sabes, te lo explico por encima: un path es una ruta de acceso a un fichero... ¿comor? Pues eso, si quieres guardar la información en el disco, tendrás que saber en que parte del disco la quieres guardar, incluso en que disco quieres almacenarla. Y lo más importante, cómo vas a llamar el sitio en el que se guardará. Esto es un poco como las variables, si quieres tener distintas cosas en la memoria del Basic, usas distintos nombres de variables, pues lo mismo con los ficheros, usando distintos nombres de ficheros puedes tener información diferente almacenada en el disco.
Para empezar, debes saber que tienes que usar un nombre en el que almacenar la información que quieres "conservar", para después poder acceder a ella en el momento que la necesites.
La ventaja de esto con respecto a los nombres de las variables es que puedes usar distintas partes del disco para guardar esa información, aunque el nombre "real" del fichero sea el mismo...
A ver, si quieres guardar los rascones esos que te dabas en las entregas anteriores, puedes decirle al Basic que quieres usar un fichero que se llame: rascones. Pero suponte que quieres tener todos los rascones de todos los meses del año almacenados en distintos ficheros, uno para cada mes. Podrías hacer algo como esto: darle a cada fichero un nombre diferente o bien usar la "extensión" del fichero para cada uno de los meses...
Por ejemplo: rascones.ene para enero, rascones.dic para los de diciembre... etc.
Y si quieres que esos datos se guarden en el disco A, pues sólo tienes que decirle que el fichero se llama: A:\rascones.ene
Si tienes la intención de guardar cada grupo de ficheros en carpetas (directorios) diferentes, también puedes indicarselo en la ruta esta de acceso: C:\Datos\A1998\rascones.ene
Por supuesto para poder hacer esto último debes tener un disco C (¿quién no lo tiene?), un directorio A1998 que está dentro de otro llamado Datos que está a su vez en el directorio raíz del mencionado disco C.
En caso que no se especifique la ruta completa, el Visual Basic usará el directorio actual para acceder al fichero.

Debes saber que el visual creará el fichero indicado, pero si no existen los directorios o no puede tener acceso a ellos, dará error y no abrirá el fichero. ¿Que error? El número 76: Path not found (No se ha encontrado la ruta de acceso)
Hay más errores, muchos, pero estos ya te los irás encontrando y en su momento veremos cómo poder detectarlos.

Veremos también cómo crear las rutas esas de acceso, en caso de que no existan, para así asegurarnos que existen antes de guardar la información en el disco... pero todo a su debido tiempo...

Ahora lo que vamos a ver es unos ejemplos de cómo guardar información y después poder "leerla", ya que esto es lo más básico y lo que en principio debemos saber.

 

¿Cómo guardar la información?
Ya te he dicho antes de que con Print se puede guardar la información en el disco, veamos cómo:
Print #NumFic, Nombre
Print #NumFic, 125

También podemos guardar esta misma información así:
Print #NumFic, Nombre, 125

Es decir que si quieremos guardar varias cosas con una misma instrucción, lo haremos usando una coma como separador. De esta forma cada cosa que esté separada se guardará en el disco en "líneas" distintas.

 

¿Cómo leer la información?
Para poder leer la información, además de abrir el archivo para lectura modo INPUT, hay que usar una de estas instrucciones:
Input #NumFic, Variable
También con: Line Input #NumFic, variable.

La diferencia entre el Input y el Line Input la veremos dentro de un ratillo.
Antes tendremos que ver cómo acceder a ese nombre y a ese número que antes hemos guardado...
Input #NuFic, unNombre, unNumero

Un detalle que debes tener en cuenta es que si el Nombre que guardamos tiene alguna coma, puede que no accedas a los datos como pretendías... Vamos a verlo con un ejemplo. Crea un nuevo proyecto en el VB y añade dos botones (CommandButton), escribe este código y pruebas:

Private Sub Command1_Click()
    Dim Nombre$, Num%
    Dim NumFic%

    Nombre = "Pérez, Pepito"
    Num = 22

    NumFic = FreeFile
    Open "C:\Prueba.txt" For Output As NumFic
    Print #NumFic, Nombre, Num
    Close NumFic

End Sub
Private Sub Command2_Click()
    Dim Cadena$, Numero%
    Dim nF%

    nF = FreeFile
    Open "C:\Prueba.txt" For Input As nF
    Input #nF, Cadena, Numero
    Close nF

    MsgBox "Cadena= " & Cadena & vbCrLf & _
           "Número= " & Numero

End Sub

Ahora pulsa en F5 y dale primero al botón Command1, después le das al Command2 y verás que no te muestra lo esperado.
En lugar de mostrar:
Cadena= Pérez, Pepito
Número= 22

Te ha mostrado:
Cadena= Pérez
Número= 0

¿Que ha ocurrido?
En primer lugar, decirte que esto mismo con el Basic del MS-DOS hubiese dado un error, pero debido a como maneja el VB las variables, se ha tragado lo que ha encontrado... ¿Que ha encontrado? Pues que tiene que asignar a Cadena la "palabra" Pérez y a la variable Numero el "número" Pepito... que al no ser un número, le ha dado el valor cero...

Esto es debido a que cuando INPUT lee los datos espera una coma o el final de línea para "distinguir" entre los diferentes datos a asignar a las variables indicadas.
Vale, dirás, pongámoslo en distintas líneas y así los leerá correctamente:

Input #nF, Cadena
Input #nF, Numero

Pero con esto no lo solucionarás, pruébalo y verás que tengo razón.
¡De gente desconfiada está el mundo lleno! ...no te he dicho que daría el mismo resultado... HUM!

Bien, ¿cómo solucionarlo?
¿Lo has adivinado? Pues eso mismo, usando el Line Input... Pero con Line Input no se pueden especificar más de una variable en la misma instrucción... así que ponlas en dos líneas.

Line Input #nF, Cadena
Line Input #nF, Numero

¡OPS! ¿Que ha ocurrido?
Si has pulsado simplemente F5, te habrá dado un error al pulsar en el segundo botón... Y si has pulsado Control+F5, te habrá indicado, con el mismo error, que los tipos no coinciden, (si usas la versión inglesa: Type Mismatch)

Esto es debido a que Line Input sólo puede leer cadenas de caracteres, mejor dicho sólo se pueden usar variables de tipo string (cadena), ya que esta instrucción lee todo lo que hay en la línea actual del fichero abierto, hasta el final de la línea.

¿Cómo solucionarlo?
Usando una variable intermedia o simplemente usando el INPUT normal para leer el número.
Veamos cómo sería de las dos formas:

Line Input #nF, Cadena
Input #nF, Numero

Dim sTmp$

Line Input #nF, Cadena
Line Input #nF, sTmp
Numero = Val(sTmp)

Ahora si que tendremos el resultado correcto:
Cadena= Pérez, Pepito
Número= 22

¡EXACTO! Tampoco nos ha mostrado esto...
¿Por qué?
Muy sencillo, realmente no es sencillo, sino que después de que me haya ocurrido como dos millones de veces, resulta hasta lógico... 8-(
Si miras el contenido del fichero C:\Prueba.txt, te darás cuenta de que el contenido de este fichero es:
Pérez, Pepito 22
Entre Pepito y el 22 hay un tabulador, Chr$(9). Esto es debido a que Print x, y muestra los valores en distintas "posiciones" de tabulación, lo mismo ocurre cuando se guarda en el disco...
Para solucionar todo esto y hacer que la cosa funcione bien, te aconsejo que cada dato lo guardes con distintas instrucciones Print, de esta forma cada dato se guarda en distintas líneas del fichero.
Así que cambia el código del Command1, para que en lugar de un sólo Print, haya dos:

Print #NumFic, Nombre
Print #NumFic, Num

Ahora todo debe funcionar bien.
Vale, pruébalo si no te fías...
¿Tenía yo razón? Pues claro, ...ya que lo he comprobado antes... ;-)

Si no sabemos el tipo de datos que tenemos almacenado, lo mejor es usar la instrucción Line Input y así nos curamos en salud, pero si sabemos que, por ejemplo, todos los datos son numéricos y se han almacenado sin usar comas...

Mejor un ejemplo:
En este caso vamos a guardar en un array una serie de números aleatorios, los vamos a guardar en un fichero y después los leeremos para asignarlos en otro array y los mostraremos en un label.

Para hacerlo, crea un nuevo proyecto, el anterior lo puedes borrar ya que es de una inutilidad total.
Añade un Label que ocupe prácticamente todo el Form, salvo la parte de abajo, en la que pondrás dos botones.
Pega el código este que te pongo, pulsa F5 y primero pulsa en el Command1, para después pulsar en el Command2

Private Sub Command1_Click()
    Dim Numeros(1 To 10) As Integer
    Dim i%
    Dim nFic%

    Randomize

    'Asignamos los valores
    For i = 1 To 10
        Numeros(i) = Int(Rnd * 100) + 1
    Next
    'Abrimos el fichero
    nFic = FreeFile
    Open "C:\Prueba.txt" For Output As nFic
    For i = 1 To 10
        Print #nFic, Numeros(i)
    Next
    Close nFic
    Label1 = "Números guardados en el disco"
End Sub


Private Sub Command2_Click()
    Dim MasNumeros(1 To 10) As Integer
    Dim i%
    Dim nFic%

    'Abrimos el fichero para leer los datos
    nFic = FreeFile
    Open "C:\Prueba.txt" For Input As nFic
    For i = 1 To 10
        Input #nFic, MasNumeros(i)
    Next
    Close nFic

    'Asignamos estos números al label:
    Label1 = ""
    For i = 1 To 10
        Label1 = Label1 & MasNumeros(i) & vbCrLf
    Next

End Sub

Este es un ejemplo sencillo de cómo asignar datos a un array, guardarlos en el disco y después leerlos.

Y hasta aquí hemos llegado...

Como ejercicio, haz un programa que al pulsar en un botón, te pida diez nombres, los guarde en un fichero y después pulsando en otro botón los muestre en un label.
No es necesario que uses un array para guardar los datos, pero podrías hacer dos versiones, con y sin un array.

Como pista te recordaré que la función InputBox puede servirte para esto de preguntar, ya que el valor que devuelve es la cadena de caracteres introducida en la caja de diálogo que muestra.
Esto del InputBox ya lo vimos en la novena entrega, o en las soluciones, pero te explico brevemente cómo funciona:
variable$=InputBox("Escribe un nombre")
¿Facil, verdad? Pues esa es toda la pista que te voy a dar.

Ahora se "legal" y no veas las soluciones de esta entrega hasta que lo hayas hecho tú.

En la página de las soluciones tienes un "extra", así que aunque sepas cómo hacerlo... te pasas a verla... ¿vale?

Espero que te haya resultado instructiva esta entrega, a pesar de haberte dejado con la miel en la boca, pero así son las cosas y no es plan de darlo todo de golpe.
¿Para cuando la siguiente entrega? ¡Ah!, misterios de la vida... eso ni se sabe. Así que permanece a la escucha y ya verás cuando... no quiero prometer que será pronto, que después me regañas... así, que... ¡a esperar!

Si hay algo que no entiendas o simplemente quieres hacer algún comentario sobre esta entrega o cualquier otro tipo de peloteo o lo que te de la gana decirme sobre el curso básico, usa este link...
Pero no lo aproveches para las consultas... ¡que te conozco rosco!

Nos vemos pronto.
Guillermo


 
entrega anterior ir al índice siguiente entrega

Ir al índice principal del Guille