La sección se llama
"elGuille" y los dos campos son "nombre" y
"email"
Realmente para acceder a este tipo de ficheros no necesitaríamos
usar Seek, ya que podemos acceder secuencialmente, pero vamos a ver
cómo podemos "posicionarnos" en una sección en concreto,
después de haber leído el contenido y haber tomado "buena
nota" de las posiciones.
La utilidad de ejemplo, nos va a
mostrar todas las secciones disponibles y después podremos acceder
rápidamente a una posición en concreto.
Veamos el aspecto del formulario y el código correspondiente:

'Esta fecha no está mal, es que ya lo tenía "manuscrito" desde entonces...
'Ejemplos del curso básico, ejemplo de Seek (26/May/98)
'
Option Explicit
Private Type tSecciones
Nombre As String
Posicion As Long
End Type
Private aSecciones() As tSecciones
Private nSecciones As Integer
Private sFic As String
Private nFic As Integer
Private Sub Form_Load()
'deshabilitar el botón de leer contenidos
cmdLeerContenido.Enabled = False
Text1 = ""
List1.Clear
'Creamos el fichero de ejemplo
sFic = "basico_20.ini"
nFic = FreeFile
Open sFic For Output As nFic
Print #nFic, "[elProfe]"
Print #nFic, "Nombre=Guillermo"
Print #nFic, "email=guille@costasol.net"
Print #nFic, ""
Print #nFic, "[Alumnos]"
Print #nFic, "Cantidad=2"
Print #nFic, "Nombre_01=Pepito"
Print #nFic, "email_01=pepito@servidor.com"
Print #nFic, "Nombre_02=Juanita"
Print #nFic, "email_02=juani@servidora.net"
Print #nFic, ""
Print #nFic, "[Fecha]"
Print #nFic, "Fichero creado el día=26/May/1998"
Print #nFic, "Fichero actualizado el día=" & Format$(Now, "dd/mmm/yyyy")
Close
End Sub
Private Sub cmdLeerContenido_Click()
'Leemos el contenido de la sección seleccionada en el list
Dim sCadena As String
Dim nItem As Long
nItem = List1.ListIndex
If nItem >= 0 Then
'borramos el contenido del Text1
Text1 = ""
nFic = FreeFile
Open sFic For Input As nFic
'posicionamos el fichero en el sitio que nos interesa
Seek nFic, aSecciones(nItem + 1).Posicion
'ahora leemos el contenido del fichero hasta encontrar [
'o hasta que se acabe el fichero
Do While Not EOF(nFic)
Line Input #nFic, sCadena
If Left$(sCadena, 1) = "[" Then
'nada más que leer
Exit Do
Else
Text1 = Text1 & sCadena & vbCrLf
End If
Loop
Close nFic
End If
End Sub
Private Sub cmdLeerSecciones_Click()
Dim sCadena As String
Dim Posicion As Long
'Borramos el contenido del ListBox
List1.Clear
'Leemos las secciones disponibles
nFic = FreeFile
Open sFic For Input As nFic
Do While Not EOF(nFic)
Line Input #nFic, sCadena
'guardamos la posición actual, justo después de leer,
'de esta forma nos indicará la posición a partir de la
'cual leeremos el contenido...
Posicion = Seek(nFic)
'Si es una sección
If Left$(sCadena, 1) = "[" Then
'incrementamos el número de secciones
nSecciones = nSecciones + 1
'redimensionamos el array
ReDim Preserve aSecciones(nSecciones)
'asignamos los valores al array
With aSecciones(nSecciones)
.Nombre = sCadena
.Posicion = Posicion
End With
'añadimos esta sección a la lista
List1.AddItem sCadena
End If
Loop
Close nFic
If nSecciones Then
'MsgBox "Se han hallado " & nSecciones & " secciones"
'seleccionamos el primer item del listbox
List1.ListIndex = 0
'habilitamos el botón
cmdLeerContenido.Enabled = True
Else
MsgBox "No hay secciones en el fichero: " & sFic
End If
End Sub
Private Sub List1_DblClick()
'También podemos ver el contenido de una sección
'haciendo doble-click
cmdLeerContenido_Click
End Sub
Te explico un poco cómo funciona
todo esto. Ya que de lo que se trata no es sólo de ver código sino
de explicarlo, ¿verdad?
En primer lugar declaramos las
variables que se van a usar.
Una de estas variables es un tipo definido que contendrá el nombre
de la sección y la posición dentro del fichero.
Creamos un array dinámico (es decir redimensionable) de este nuevo
tipo de datos, en él guardaremos cada una de las secciones halladas
en el fichero procesado. También dimensionamos una variable que
contendrá el número de secciones halladas, aunque sólo se usa
mientras se lee la información del fichero, por tanto no es
necesario que esté declarada en la parte general de las
declaraciones del formulario.
Recuerda que las variables declaradas en la parte general de un
formulario, están disponibles en todo el formulario.
En el Form_Load, que es el punto de
entrada de nuestra utilidad, además de asignar el nombre del
fichero y guardar un contenido de ejemplo, borramos el contenido del
Text1 y el List1, además deshabilitamos el botón de leer el
contenido de una sección, para que no se use hasta que no haya
datos.
Al pulsar en el botón que lee las
secciones, primero borramos lo que hubiese antes en el array de
secciones y asignamos cero a la variable que contiene el número de
secciones.
Después de abrir el fichero, en modo secuencial, vamos leyendo
línea por línea, en cuanto nos encontramos con una línea que
empieza por corchete [, quiere decir que hemos encontrado una
sección, por tanto, incrementamos la variable que lleva la cuenta
de las secciones halladas, redimensionamos el array usando Preserve
para no perder la información antes almacenada, y asignamos la
información del nombre y la posición que hemos obtenido con Seek.
Fíjate que la lectura de la posición se hace después de haber
leído la sección del fichero, esto es así, porque lo que
necesitamos saber es la posición que viene a continuación de la
sección, ya que después de la sección es cuando vienen las
claves. (En realidad, se asigna siempre después de leer una línea,
pero a nosotros sólo nos interesa su valor cuando hemos encontrado
una sección).
Seguimos leyendo hasta encontrar el final del fichero.
¿Por qué se ha usado el acceso
secuencial?
Por la sencilla razón de que este tipo de fichero suele ser de tipo
ASCII, es decir que no contiene caracteres "raros" y que
normalmente se editan en programas del tipo NotePad. De hecho el
Windows tiene asociado al bloc de notas (Notepad) para abrir los
ficheros que contengan la extensión INI.
Además de que al no saberse la longitud de los datos que contiene,
pero que si sabemos que cada línea termina con un retorno de carro
(o cambio de línea), es más cómodo usar el Line Input # para leer
toda la línea; el modo binario no nos sería de utilidad, salvo que
leyésemos el fichero caracter por caracter, cosa que ralentizaría
el proceso.
Para acceder a una sección en
concreto, cosa que ocurre al pulsar en el botón cmdLeerContenido,
simplemente abrimos el fichero, posicionamos el "puntero"
en el sitio adecuado y leemos lo que haya en el fichero hasta que
encontremos otra sección, (que empezará por un corchete), o hasta
que lleguemos al final del fichero.
También he puesto código para que al hacer doble-click en un
elemento del List1, se lea el contenido de la sección
correspondiente, para ello lo único que se hace es llamar al evento
Click del botón cmdLeerContenido.
Y hasta aquí ha llegado esta
entrega, (que realmente formaba parte de la entrega 19), ahora vamos
a ver un par de ejercicios para que te vayas soltando en esto de la
programación con el Visual Basic.
El primer ejercicio realmente no
usa Seek pero si algo parecido a la utilidad esta de leer el
contenido de los ficheros del tipo INI, y consiste en crear un array
con el contenido de todas las secciones y todas las claves y valores
de cada sección. De forma que el fichero sólo se lea una vez y
cuando se quiera mostrar el contenido de una sección se use el
contenido del array.
La verdad es que no es nada fácil, pero tampoco pienses que es tan
complicado como para no poder resolverlo, al menos deberías
intentarlo y no coger el camino fácil de ver la solución, entre
otras cosas, porque lo que se pretende con estos ejercicios es que
cojas "soltura" en la programación y si además de
soltarte te quedas con las "buenas" costumbres, pues
mejor.
¿A que buenas costumbres me refiero?
A usar Option Explicit en todos los módulos, para de esta forma
declarar las variables antes de usarlas y a "indentar" el
código para que te sea más fácil seguirlo...
Después del sermón vamos a ver la pista que te doy:
La pista es que puedes usar estos tipos definidos para crear el
array de claves y su contenido, y el array para almacenar cada
sección y las claves de cada una de ellas.
'
Private Type tContenidos
Clave As String
Contenido As String
End Type
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As tContenidos
End Type
Private aSecciones() As tSecciones
Como sabes cada clave tiene este
formato: Clave=Contenido. Esto te lo digo para que la clave vaya por
un lado y el contenido por otro, aunque sea algo más complicado que
almacenar simplemente la clave y el contenido, a la larga te
ayudará a manipular mejor las cadenas de caracteres y también le
darán mayor utilidad al código que se cree con este ejercicio.
Como segundo ejercicio, haz lo
mismo, pero en lugar de almacenar en el array cada clave y su
contenido, usa Seek para "recordar" la posición de cada
una de las claves de cada sección para después poder acceder a esa
parte del fichero para leer lo que nos interesa.
Este segundo ejercicio es un poco
más complicadillo, ya que necesitará usar de forma correcta Seek,
tanto en modo función como en modo instrucción.
Este es el tipo de datos que tendrás que usar:
'
Private Type tSecciones
Nombre As String
NumClaves As Integer
Contenidos() As Long
End Type
Private aSecciones() As tSecciones
Fíjate que aquí sólo guardamos
en Contenidos la posición de cada clave dentro del fichero.
Suerte y no desesperes si no lo
consigues, no me gustaría perder a todos mis alumnos de golpe...
creo que no lo soportaría.
Las
soluciones de los dos ejercicios están en este link.
Y ya sólo queda que hagas tu
comentario sobre esta entrega.
Y si hay algo que necesites que te aclare, relacionado con lo que se
ha visto en esta entrega, no te cortes y pregúntame, pero sólo
relacionado con lo que estamos viendo, ¿vale?
Nos vemos.