Más
sobre acceso a ficheros aleatorios
|
Realizamos
programas para la gestión de empresas. Empresas medianas y
pequeñas. Programas de contabilidad, cartera de pedidos
clientes proveedores, facturación control de albaranes,
tesorería cartera de cobros y pagos y estadísticas.
Nuestro
agradecimiento a todos los que por unas causas o por otras
visitan nuestra web. Gestión de empresas PYMES. Curso de
programación de Visual Basic.
|
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 anteriormente... 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
"vacíos" 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 supuesto, queremos que los
registros que haya sigan conservando los datos que tuviesen... sino,
¿que clase de rutina conversora sería?
Acuérdate 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 oído 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.