Curso Básico de Programación
en Visual Basic
Entrega
Dieciocho: 26/Abr/98
por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el índice lo puedes hacer
![]()
Ya es hora de seguir con los ficheros de acceso aleatorio, después del alto en el camino para ver cómo se manejan las cadenas de caracteres en Visual Basic, aún no hemos visto todas las funciones, pero si las más comunes. No te preocupes... no voy a continuar en esta entrega con esas funciones... ya le llegarán el turno...
¡Por fin! Habrás exclamado... y con razón... pero son cosas que debes saber... y como de lo que se trata es de saber más y/o mejor, pues... nunca están de más...
No recuerdo exactamente en que punto me quedé en las explicaciones sobre el acceso aleatorio de la entrega dieciséis, así que... si ves que me repito, pues... ¡salud! y a seguir adelante...
Una cosa que hay que tener superclarísimo en esto del acceso aleatorio, es que debemos usar tipos definidos para acceder a los datos del fichero... ¿para que complicarnos con funciones conversoras de datos, si el Visual lo hace de forma automática por nosotros? Por tanto, te aconsejo que "siempre" uses variables definidas, ya que no hay un motivo válido para no usarlas.
En los siguientes ejemplos, vamos
a usar el tipo definido que usamos en la entrega dieciséis, el
del colega...
En este primer caso, vamos a guardar en un registro determinado
el contenido de tres cajas de textos, cada una de ellas para cada
uno de los campos del tipo definido:
Private Sub cmdGuardar_Click()
Dim unColega As t_colega
Dim nFic As Long
Dim numColega As Long
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
'Sacar un valor aleatorio
numColega = Rnd * 25 + 1
Label1(3) = "número de colega: " & CStr(numColega)
With unColega
.Nombre = Text1
.Edad = Val(Text2)
.email = Text3
End With
'Guardar los datos en el disco
Put #nFic, numColega, unColega
Close nFic
End Sub
Aquí vemos los pasos que
normalmente se realizan con cualquier tipo de fichero...
--Se asigna a una variable un número de fichero libre (ya sabes:
el canal por el cual VB se comunicará con el disco)
--Se abre el fichero en cuestión, recuerda que las extensiones
que uses son a tu antojo, no hay necesidad de usar un tipo de
extensión específica, salvo que hagas un programa que
"entienda" los datos contenidos en ese tipo de
extensión y puedas abrir los ficheros con sólo hacer doble
click... pero esto es un tema para más adelante...
--Se asigna a la variable el dato a guardar y
--Se guarda...
Este ejemplo no sería práctico,
ya que puede que salga el mismo número más de una vez y se
perderían los datos anteriores.
Porque debes saber que, cuando se guarda información en un
registro determinado, éste funciona de la misma forma que las
variables... o casi, es decir: cuando se guarda un nuevo valor,
el que hubiera antes "desaparece".
Una cosa que debes saber, aunque
me imagino que lo habrás comprobado al ejecutar el programa, y
si no ha sido así, no te preocupes... si te sirve de consuelo,
tarde unos mesesillos en "detectar" esto que te voy a
explicar ahora...
Puedes acceder a cualquier registro de un fichero aleatorio,
incluso si antes no has guardado nada. De la misma forma, puedes
guardar información en el registro 7 aunque antes no hayas
guardado en ninguno de los 6 anteriores.
¿El problema?
Que si lees información de un registro en el que no has guardado
información anteriomente... puedes encontrarte con
"basura", y de hecho la encontrarás...
¿Por qué?
Porque accedes a una parte del disco que, posiblemente tenía
guardada alguna otra información... aprovecho esto, para decirte
que, cuando borras un fichero del disco, este fichero no se
borra, al menos no se borra la información que contenía.
¿Cómo solucionar este problemilla?
Hay varios métodos, el que yo normalmente usaba, ahora casi no
trabajo con ficheros de acceso aleatorio, era guardar
información "vacía" en unos cuantos registros y
cuando esos estaban ocupados, guardaba otro puñado y así.
Algunas veces, si sabía que el fichero iba a tener un número
limitado de registros, los grababa todos con datos vacíos, es
decir cadenas con sólo espacios y números con valor cero.
En otras ocasiones tenía un campo del registro al que le
asignaba un valor, si al leer el registro, tenía ese valor
"predeterminado", quería decir que ya contenía
información válida, si no era así, ponía los campos con
valores "vacios" y así evitaba la basura.
Si quieres comprobarlo... así de paso me sirve para que veas un ejemplo de cómo acceder a los datos del disco y mostrarlo en unas cajas de texto.
Private Sub cmdLeer_Click()
Dim unColega As t_colega
Dim nFic As Long
Dim numColega As Long
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
'Sacar un valor aleatorio
numColega = Rnd * 25 + 1
Label1(3) = "número de colega: " & CStr(numColega)
'leer ese registro
Get #nFic, numColega, unColega
With unColega
Text1 = .Nombre
Text2 = .Edad
Text3 = .email
End With
Close nFic
End Sub
Si has probado el ejemplo de guardar, para poder conseguir datos con contenido "basura", deberás probar algunas veces más que las que hayas probado antes... ¿por qué? porque estamos usando números aleatorios y al no existir un "Randomize", la secuencia de números aleatorios siempre es la misma cada vez que ejecutas el programa... ¿lo recuerdas?
Bien, aparte del asuntillo este de la "basura", no tiene ningún misterio esto del acceso aleatorio... pero aún no hemos terminado, no queda mucho para que te toque "trabajar", pero todavía tienes un respiro... si a que te explique más cosas se puede llamar respiro...
En el tercer ejemplo que vamos a ver, se van a mostrar todos los colegas que tenemos guardados en el fichero. Se supone que los datos los hemos guardado de forma ordenada, no como en los ejemplos anteriores, ya que no tiene ningún motivo guardar a los colegas aleatoriamente... no sea que cojan complejo de bola de bingo...
Ya te he comentado que la longitud
de todos los registros de un fichero aleatorio tienen
que ser iguales... y ahora lo podrás comprobar... que algunas
veces no hay que fiarse de todo lo que yo diga...
El número de registros es el resultado de dividir la longitud
del fichero por la longitud de cada registro...
numRegistros = Lof(nFic) \ Len(unColega)
Fíjate que uso \ para dividir. Las divisiones realizadas con
este signo dan como resultado números enteros, mientras que el
habitual / realiza una división de coma flotante... es decir que
puede tener decimales.
Como un registro no puede estar formado por "nosecuantos
caracteres y pico", en este caso es recomendable el
uso de la división de números enteros, entre otras cosas porque
también es más rápida...
Por tanto este código nos informaría del número de registros y haría un bucle entre todos los registros que tiene el fichero.
'
nFic = FreeFile
Open "colegas.dat" For Random As nFic Len = Len(unColega)
numRegistros = Lof(nFic) \ Len(unColega)
For i = 1 To numRegistros
Get #nFic, i, unColega
'Mostrar el contenido del registro
'...
Next
Close nFic
Podemos sustituir el Get
#nFic, i, unColega por esto otro: Get #nFic, ,
unColega.
Cuando no se indica el número de registro, tanto en Get como en
Put, Visual Basic usa el registro actual. Cada vez que se accede
a un registro determinado, el Basic lo "marca" como
registro actual, de esta forma sabe cual debe ser el siguiente
registro al que debe acceder si no se le indica ninguno.
Si hacemos esto: Get #nFic, 15, unColega, al hacer esto otro: Put
#nFic, , unColega, se estará guardando en el número 16.
Es decir, el VB mantiene un "puntero" al siguiente
registro. El bucle anterior podría haber quedado así:
For i = 1 To numRegistros
Get #nFic, , unColega
'Mostrar el contenido del registro
'...
Next
De todas formas, siempre suelo especificar el número de registro al que quiero acceder, así me parece que estoy más seguro de dónde se leerá o escribirá el registro.
Uno de los problemas que tiene
este tipo de ficheros es que estamos "atados" a la
longitud del registro.
¿Que ocurre si nos dá el "punto" de quitar, añadir o
cambiar la longitud de alguno de los campos?
Pues que lo tenemos más bien chungo... estaremos metidos en un
pequeño lio...
Una vez que hemos definido el tamaño del registro, y tenemos
datos en el fichero, cualquier cambio que hagamos, dará como
resultado algo no esperado...
Pero, todo tiene arreglo... aunque en este caso, nos lo tendremos
que "currar" nosotros. Tendremos que fabricarnos alguna
rutina que se encargue de esta conversión.
Y ese podría ser el ejercicio de
esta entrega:
Realizar una pequeña utilidad que convierta un fichero de acceso
aleatorio con registros de una longitud conocida, en otro con
registros de otra longitud o con campos de longitud diferente al
original.
Y digo "longitud conocida", porque si no sabemos la
longitud de cada registro, incluso de cada campo de ese registro,
poco podremos hacer...
Un detalle importante es que para
acceder a los ficheros abiertos como "random", sólo
podemos hacerlo con variables de longitud fija, ya sean tipos
definidos o cadenas.
Se podría pensar que haciendo esto:
Dim unaCadena As String 'Asignamos 83 espacios a esta cadena unaCadena = Space$(83) nFic = FreeFile Open "colegas.dat" For Random As nFic Len = Len(unaCadena) '... Get #nFic, 1, unaCadena
¡Pues no!
Ya que la variable unaCadena no tiene longitud
fija y el Visual Basic necesita que lo sea.
Otra cosa es que hagamos esto otro:
'Esta cadena siempre tendrá este número de caracteres Dim unaCadena As String * 83 nFic = FreeFile Open "colegas.dat" For Random As nFic Len = Len(unaCadena) '... Get #nFic, 1, unaCadena
Ahora si que funcionaría bien la
cosa, ya que el VB tiene la información que necesita...
La verdad es que hecho de menos una instrucción que tenía el
Basic del MS-DOS y era que podías definir una serie de variables
para acceder a los registros, incluso podías declarar una
array... y cada uno de los elementos del array con la longitud de
cada uno de los campos... Pero eso ya no está, así que... hay
que usar los tipos definidos que al fin y al cabo es la mejor
opción para este tipo de ficheros.
Para el ejercicio, se supone que tenemos un fichero con registros declarados de esta forma:
Private Type t_Colega
Nombre As String * 30
Edad As Integer
email As String * 50
End Type
Y lo queremos convertir en registros que tengan esta otra:
Private Type t_Colega
Nombre As String * 30
Edad As Integer
email As String * 50
URL As String * 128
End Type
Por supesto, queremos que los
registros que haya sigan conservando los datos que tuviesen...
sino, ¿que clase de rutina conversora sería?
Acuerdate de lo que digo en muchas ocasiones, no pienses en
complicarte la vida, siempre procura ir a lo simple, ya que en la
mayoría de las ocasiones ese es el camino correcto...
Cuando veamos la siguiente entrega, o al menos cuando veamos los ficheros de acceso binario, (mi intención es que sea en la próxima entrega, pero ya sabes...), crearemos otra utilidad de conversión más flexible que esta, es decir, una rutina que convierta un fichero a un formato que pueda ser definido por el usuario en tiempo de ejecución.
Aunque no sea lo habitual, y
normalmente una entrega termina cuando te pongo los ejercicios,
vamos a ver un ejemplo completo para introducir y mostrar datos
en un fichero de acceso aleatorio.
¿Cómo?
¿Que quieres hacerlo tú?
Pues vale, me parece estupendo...
Desde luego, es que tengo unos alumnos que no me merezco... 8-)
No te quejes... y no digas que tú
no has dicho nada... yo he oido voces que me decían: ¡queremos
hacerlo nosotros!
Y eso es lo que hay...
Para esta aplicación vamos a usar
tres cajas de texto en los que introduciremos los valores a
guardar en cada campo, con sus correspondientes labels para
indicarnos los nombres de esos campos.
Existirá otro label/textbox para indicarnos el número del
registro actual, es decir en el que se almacenarán los datos o
del que se leerán esos datos.
Un par de botones para Guardar y Leer...
¿Te resulta familiar?
Pues así es... algo parecido a lo que ya vimos en la entrega
número once cuando se usaron arrays de tipos definidos...
El aspecto del "programilla" sería algo así:

No he añadido nada para mostrar todos los registros... pero ya tendremos tiempo de hacerlo.
Bueno, pues hasta aquí hemos
llegado...
Las soluciones
de la entrega 18 están en
este link.
Y a pesar de parecer un poco pesado, realmente me gustaría recibir tu opinión sobre esta entrega.
Nos vemos.
Guillermo
![]()