Curso Básico de Programación
en Visual Basic
Entrega
Diecinueve: 24/Jun/98
por Guillermo "guille" Som
Si quieres linkar con otras entregas, desde el índice lo puedes hacer
![]()
Sé que va a sonar a excusa barata
y esas cosas, pero si te dijera que el "manuscrito" lo
tengo terminado desde el 26 de mayo...
Ahora ya no es por aquello del portátil, aún no lo tengo,
parece ser que no hay "almas" tan bondadosas por esos
mundos de Internet... pero bueno...
Estaba pensando yo que lo mismo con un programilla de esos a los
que les hablas y escriben de forma automática... la verdad es
que he estado probando con el SDK que tiene Microsoft, pero ese
no me termina de valer, salvo que las entregas las escriba en
yankinglish... pero no es plan... en fin, tendré que seguir
buscando las teclas y después de pulsar una tecla mirar para el
papel...
Bueno, menos rollo, a ver si soy capaz de terminarlo pronto, para
irme a ponerme como un salmonete, que hoy es día de playa,
además de que es fiesta local y esas cosas pa que los catetillos
podamos ir a darnos un remojón a la playa, con una buena torta
de San Juan...
Me acuerdo yo que antes... ¡vale, vale!, no hace falta que
grites..., lo dejo, pero que sepas que te pierdes lo que iba a
decir...
Para terminar con los tipos de
acceso a ficheros, vamos a ver la forma más potente y a la vez
la más complicada... o casi.
Con el acceso binario podemos acceder a cualquier punto del
fichero y, lo más importante, leer o guardar la cantidad de
caracteres que queramos.
Antes de entrar en detalles,
veamos cómo indicarle al VB que vamos a usar este tipo de
acceso.
Como siempre, esto se hará al abrir el fichero:
Open Nombre_Fichero For Binary As Numero_Fichero
Cuando abrimos un fichero en modo binario, al igual que sucedía en el modo aleatorio (random), se tiene acceso tanto de lectura como de escritura. También se usan las instrucciones GET y PUT para leer o escribir la información, pero a diferencia del acceso aleatorio, no estamos obligados a usar una variable de longitud fija, (además de longitud previamente especificada a la hora de abrir el fichero), si esto fuese así, no habría diferencia con el acceso aleatorio... así que esta entrega casi ni existiría...
¿Cómo leemos datos de un fichero de acceso binario?
Ya te he comentado que se usa GET
para leer datos, la cuestión está en cómo indicarle al Visual
Basic la cantidad de caracteres a leer...
Pues hagamos la pregunta: ¿Cómo le idicamos al VB la cantidad
de caracteres a leer?
Vamos a verlo con un ejemplo:
A$ = Space$(10)
Get nFic, , A$
Esto leerá 10 caracteres.
Osea, se leerán tantos caracteres
como "capacidad" tenga la variable usada. Si sólo
quisieramos leer sólo un caracter, esta variable tendría una
longitud de un caracter... (algunas veces alucino con mi lógica tan
contundente, en fin...)
La ventaja es obvia: no es necesario estar atados a un número
fijo de caracteres, simplemente asignándole una cantidad de
caracteres a la variable usada, es suficiente.
El problema puede surgir a la hora de determinar la posición
desde la que leeremos esos caracteres.
Ves, nada es perfecto, y si no controlamos el tema, pues,
tendremos algún que otro quebradero de cabeza.
La posición tendremos que indicarla nosotros mismos, aunque también podemos dejar que sea el propio Visual el que se encargue de este tema, todo dependerá de lo que queramos hacer.
Ya vimos en el acceso aleatorio
que el cálculo de la posición de cada registro podiamos dejarlo
de forma automática, es decir que sea el propio VB el que
"decida" la posición. Realmente el VB no decide nada,
ya que es una característica de GET y PUT, si no se le indica la
posición, usa la "predeterminada" y esa posición se
ajusta automáticamente cada vez que se lee o escribe
información, el cálculo se hace tomando la última posición y
añadiéndole la longitud del dato. En el caso de los ficheros
aleatorios esa posición es "ficticia" (o relativa), ya
que el VB convierte la posición real dentro del fichero en
número de registros... Pero ahora no estamos con el acceso
aleatorio, sino con el binario y con este tipo de acceso,
trabajamos con posiciones "reales", es decir que si
hacemos esto:
Get nFic, 3, A$
Leeremos caracteres desde la posición tres del fichero, el
número de caracteres leidos estará indicado por la longitud de
la variable A$
Como ya comenté antes, la ventaja es que no estamos obligados a leer un número determinado de caracteres y el inconveniente es que hay que saber lo que estamos haciendo y se puede conbertir en un inconveniente si no lo usamos de la forma adecuada.
Pero, vamos a demostrar esto que
acabo de decir.
Crea un nuevo proyecto, asignale a la propiedad AutoRedraw del
form el valor TRUE, de esta forma no habrá problemas a la hora
de imprimir, (y ver lo impreso), en el formulario. Esto del
Autoredraw es útil cuando nuestro form quede oculto por otra
ventana, nunca perderá lo que hayamos imprimido en él.
Añade un commandbutton y escribe el siguiente código:
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
'sCadena tiene 20 caracteres
sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , sCadena
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
Get nFic, , sCadena
Print sCadena
Close nFic
End Sub
Ejecuta la aplicación (pulsando
F5), pulsa en el Command1, y verás que todo funciona bien.
Ahora añade lo siguiente antes del Get nFic, , sCadena:
sCadena = Space$(5)
Y ejecuta de nuevo el programa.
Como verás sólo se han leido los cinco primeros caracteres de
lo que se guardó anteriormente. Es decir sólo mostrará Prueb,
porque la cadena usada para leer tiene esa cantidad de
caracteres.
Este es un detalle que deberás recordar, así que apúntatelo.
La ventaja es que podemos guardar
y leer distintos tipos de datos mezclados.
Por ejemplo, si sabemos que tenemos un tipo definido y después
una cadena de caracteres, podemos mezclarlo. Pero es importante
que a la hora de leer los datos, leamos la cantidad
"justa" de caracteres, y en el orden correcto.
Vamos a ver esto que acabo de decir.
Borra el código anterior o crea un nuevo proyecto y añade un
command y el siguiente código:
'Esto en la parte General del form
Option Explicit
Private Type t_colega
Nombre As String * 30
Edad As Integer
End Type
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim unColega As t_colega
unColega.Nombre = "Guille"
unColega.Edad = 40
'sCadena tiene 20 caracteres
sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , unColega
Put nFic, , sCadena
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
Get nFic, , unColega
Get nFic, , sCadena
'mostramos los datos leidos
Print unColega.Nombre, unColega.Edad
Print sCadena
Close nFic
End Sub
Si inviertes el orden de las variables a la hora de leer, pues causas un pequeño desastre, ya que no lees lo que esperas leer. Osea que no uses esto del acceso binario "al voleo", sino pensándolo bien.
Entonces, ¿cuando es conveniente
usar el acceso binario?
Siempre que queramos acceder a un fichero del que estimemos que
puede que no sea del tipo ASCII, es decir un fichero que pueda
contener cualquier clase de caracteres. Normalmente los ficheros
ASCII, (o los usados habitualmente para acceso secuencial),
terminan cuando se encuentra un código EOF (caracter ASCII
número 26) o cuando ya no hay más caracteres en el fichero; sin
embargo con el acceso binario sólo se "acaban" cuando
no quedan más caracteres que leer del fichero.
Por supuesto que si un fichero se ha guardado usando un tipo de
acceso, puede abrirse usando otro tipo de acceso, aunque estos
casos no son recomendables, salvo que sepamos lo que hacemos...
Veamos un nuevo ejemplo. Ya sabes, borra el código usado
anteriormente o crea un nuevo proyecto.
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , "Prueba de una cadena"
Put nFic, , vbCrLf
'Se guarda una segunda cadena
Put nFic, , "Segunda cadena"
Put nFic, , vbCrLf
Close nFic
'leer como secuencial
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
Print sCadena
Loop
Close nFic
End Sub
Como habrás comprobado, se ha
leido todo lo que había en el fichero, incluso cosas que había
de pruebas anteriores.
Ahora engañemos al VB y hagamos que piense que un fichero se ha
acabado antes de que se acabe de forma "real".
Sustituye el código del Command1 por este otro:
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim sEOF As String * 1
sEOF = Chr$(26)
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , "Prueba de una cadena"
Put nFic, , vbCrLf
'Añadimos un código de fin de fichero
Put nFic, , sEOF
'Se guarda una segunda cadena
Put nFic, , "Segunda cadena"
Put nFic, , vbCrLf
Close nFic
'leer como secuencial
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
Print sCadena
Loop
Close nFic
End Sub
Ahora sólo se ha mostrado lo
guardado antes del código almacenado en la variable sEOF.
Pero el fichero continúa teniendo lo que antes tenía. Lo que
ocurre es que cuando se abre un fichero secuencial y el VB se
encuentra con el código 26, piensa que se debe haber terminado
el fichero en cuestión.
Ahora vamos a leerlo como binario... Por supuesto, sabiendo lo
que se ha guardado y cómo se ha guardado.
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
Dim sEOF As String * 1
Dim sCRLF As String * 2
sEOF = Chr$(26)
sCRLF = vbCrLf
'sCadena tiene 20 caracteres
sCadena = "Prueba de una cadena"
sFic = "binarios_19.dat"
nFic = FreeFile
Open sFic For Binary As nFic
Put nFic, , sCadena
Put nFic, , sCRLF
Put nFic, , sEOF
'Se guarda una cadena de 15 caracteres
Put nFic, , "Segunda cadena"
Put nFic, , sCRLF
Close nFic
'leer los datos guardados
nFic = FreeFile
Open sFic For Binary As nFic
'Se leen sólo 5 caracteres de los 20 guardados
sCadena = Space$(5)
Get nFic, , sCadena
Print sCadena
sCadena = Space$(15)
'Leemos los caracteres que quedaron pendientes,
'ya que sCadena sólo leyó 5 de los 20 caraceteres que tenía
Get nFic, , sCadena
'también leemos los caracteres "extras" que se guardaron
Get nFic, , sCRLF
Get nFic, , sEOF
Print sCadena
Get nFic, , sCadena
Print sCadena
Close nFic
End Sub
Bien, ahora ya hemos conseguido
leer todo, pero fíjate en el detalle de que hemos tenído que
leer los códigos "extras" que se guardaron, es decir
el retorno de carro y el de fin de fichero. Si no lo hubieramos
hecho... pruebalo y lo compruebas...
Habrás observado una línea de más y un caracter extraño antes
de "Segunda cade"... creo que no hace falta que te
explique el porqué... ¿verdad?
Normalmente con el acceso binario
podemos leer todos los caracteres que haya en un fichero. Se
suele usar cuando no sabemos la estructura de ese fichero y
tenemos alguna forma de "interpretar" lo que leemos,
aunque esto último no se aprende en ningún curso y no hay regla
fija. En la mayoría de las ocasiones que uso el acceso binario,
es cuando quiero leer información de un fichero para buscar algo
en concreto. Ese fichero puede ser un ejecutable, una DLL o
cualquier otro tipo de fichero. Si de antemano se que es un
fichero secuencial, seguramente no lo leería como binario, ya
que el tiempo de acceso y lectura de un fichero secuencial es
menor que uno abierto como binario. Osea que se lee antes uno
abierto con For Input que con For Binary.
Esta diferencia en el tiempo de acceso es apreciable sobre todo
cuando se manejan muchos ficheros...
Hablando de leer todo el contenido
de un fichero, ya sabes que existe un función llamada Input$, a
la que se le indica el número del fichero abierto y la cantidad
de caracteres que queremos leer y nos lo devuelve para que
podamos asignarlo a una variable de cadena. El fichero que hemos
creado con el último ejemplo no es realmente un fichero ASCII,
ya que contiene caracteres binarios, es decir, caracteres que no
están en el rago ASCII del 32 al 255 (en algunos casos hasta el
código 127).
Veamos la reacción del VB ante un caso "no deseado",
es decir leer lo que no debemos leer:
'Se supone que has probado los ejemplos anteriores y que existe el fichero indicado
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
sFic = "binarios_19.dat"
nFic = FreeFile
'
Open sFic For Input As nFic
sCadena = Input$(LOF(nFic), nFic)
Close nFic
Print sCadena
End Sub
Aquí lo que se pretendía era leer el fichero de una vez. Pero como se ha abierto el fichero como secuencial, el VB ha detectado que se la leido un código de fin de fichero, precisamente antes de que se acbe el fichero y nos avisa con un magnífico mensaje de error.
Esto se soluciona, bien abriendo el fichero secuencial, pero usando EOF(nFic) para comprobar si hemos alcanzado el final del fichero o bien abriendo el fichero en modo binario y usando la función Input$.
Private Sub Command1_Click()
Dim nFic As Integer
Dim sFic As String
Dim sCadena As String
sFic = "binarios_19.dat"
nFic = FreeFile
'
Open sFic For Binary As nFic
sCadena = Input$(LOF(nFic), nFic)
Close nFic
Print sCadena
End Sub
Ahora puedes observar que se lee TODO lo que hay en el fichero, ya que al abrirlo en modo binario, no se tiene en cuenta ningún caracter especial y se lee hasta dónde se le indique.
Creo que es suficiente por hoy.
Hay más cosas, en cuanto al acceso a los ficheros, pero no vamos a alargar esta entrega, que puede ser que te empaches con tantas cosas y no es bueno.
Los ejercicios
¿Recuerdas uno de los ejercicios
de la entrega 18?
Consistía en cambiar el formato de un fichero de acceso
aleatorio en otro con los campos en otro formato (longitud de los
campos). Pues bien, con el acceso aleatorio sólo era posible si
conociamos de antemano el tamaño del registro nuevo (y, por
supuesto, la longitud de cada campo). Ahora con lo que sabes del
acceso binario y unas cuantas miles de líneas de código,
podrás hacerlo para convertir cualquier fichero a un nuevo
formato y así poder usarlo de forma genérica.
Es decir, tenemos un fichero con
una serie de campos y queremos cambiar la estructura de ese
fichero y, por supuesto, traspasar la información existente al
nuevo formato. El usuario de esta utilidad, tendrá que saber la
estructura del fichero de origen y también saber la nueva
estructura a la que quiere convertir el susodicho fichero de
datos.
Para no complicar demasiado la cosa, vamos a usar sólo 10
campos, pero se podrían permitir más...
El aspecto del form en tiempo de
diseño sería el siguiente:
No te preocupes por los "campos" que faltan en el
destino, enseguida te explico cómo hacer que aparezcan, al menos
a la hora de ejecutar el programa.
Esto te servirá para otras veces en las que necesites crear
controles en tiempo de ejecución y posicionarlos adecuadamente,
o casi...
Veamos el aspecto del form y después veremos el código usado
para "crear" esos controles:

El código:
Private Sub Form_Load()
Dim i As Integer
'Crear los controles de destino
'(empezamos por UNO porque el control CERO ya está creado)
For i = 1 To 9
'Cargarlos en memoria
Load lblDest(i)
Load txtDestTam(i)
'Asignarles la posición y hacerlos visible
With txtDestTam(i)
.Visible = True
.Top = txtDestTam(i - 1).Top + .Height + 45
lblDest(i).Top = .Top - 15
lblDest(i).Visible = True
lblDest(i) = "Campo " & i + 1 & ":"
End With
Next
'Borrar el contenido de los TextBoxes
For i = 0 To 9
txtTam(i).Text = ""
txtDestTam(i).Text = ""
Next
End Sub
La cuestión está en que al
pulsar en el botón de convertir el fichero, antes se hayan
asignado los valores correspondientes.
La información que hay que pasarle a la aplicación de cada
campo, es la siguiente: tamaño de cada campo.
Lo que hay que saber es el tamaño de los números al guardarlo
en disco, para ello echale un vistazo a la ayuda del VB y te
dirá lo que ocupa cada tipo, aunque creo que en alguna de las
primeras entragas ya lo vimos.
Para muestra, un botón: Los Integers ocupan dos bytes, los Longs
cuatro bytes, etc.
La cuestión es que se asignen los valores de forma correcta, sino, la cosa puede no funcionar.
Y con esto y un bizcocho... hasta
otra entrega, que no creo que sea mañana a las ocho...
Este es el link a la solución de esta entrega, recuerda no hacer trampas e intentarlo
primero.
(De todas formas, el link no te llevará a ningún sitio, ya que
aún no la he puesto... je, je...)
Nota 25/Jun/98: Ya está operativo el link de la solución al ejercicio.
Y continuando con la sana costumbre de recibir tus preciados, y la mayoría de las veces aduladores, comentarios, cosa que agradezco y que dicho sea de paso, es la única razón por la que sigo con el curso básico... pues eso, aqui te dejo el link para que me escribas lo que te ha parecido esta entrega, pero, recuerda: no para hacer consultas, gracias.
Nos vemos.
Guillermo
![]()