Los archivos de acceso aleatorio nos permiten ir directamente a recuperar el registro deseado, sin necesidad de leer antes todos los anteriores. Solucionan de esta manera la principal limitación de los archivos de acceso secuencial, que era precisamente su método de acceso a los datos, la necesidad de recorrer todo el fichero desde el principio hasta llegar al punto que nos interesaba. Esta limitación se hacia cada vez más grande, según aumentaba el tamaño de nuestro fichero. Con un alto número de registros, los tiempos de lectura podían extenderse demasiado, hasta el punto de ser muy poco operativos y propiciar la migración a un fichero de acceso aleatorio.

Es importante reseñar que nuestra “base de datos”, si puede llamarse así, continuaba siendo un fichero.

He dicho antes que en los archivos de acceso aleatorio, podíamos ir directamente a recuperar el registro deseado, sin necesidad de leer antes todos los anteriores. Para ello era necesario conocer exactamente en que posición, dentro del archivo, se encontraba el registro que buscábamos. Pero.., ¿Cómo era posible saber en que posición se encontraba un registro?.

Básicamente, empleando dos reglas:

  • La longitud de registro estaba estrictamente definida. Es decir, todos los registros tenían la misma longitud, ocupaban el mismo espacio en memoria.
  • Y se emplea el número de registro, para posicionarnos en el registro deseado.

Siguiendo estas sencillas reglas, resultaba muy fácil saber en que posición de memoria comenzaba un registro. Supongamos que cada registro ocupaba 50 bytes, si queremos recuperar el registro 5 teníamos que irnos a leer a la posición 201 y acabábamos en la 250 (el registro 1 se extendería de la posición 1 a la 50, el registro 2 de la 51 a la 100, el 3 de la 101 a la 150, el 4 de la 151 a la 200, y finalmente el registro 5, de la posición 201 a la 250).

Características de los archivos de acceso aleatorio

Después de lo visto en el ejercicio anterior, ya tenemos que ser capaces de apuntar las principales características de los archivos de datos de acceso aleatorio:

  • Longitud fija de registro: Definimos una longitud de datos fija para cada campo y por extensión, para el registro.
  • Posicionamiento instantáneo al principio del registro a recuperar: No hay que recorrer el fichero desde el principio, como ocurría con los archivos de acceso secuencial.
  • Admiten apertura mixta: Podemos abrir el fichero de forma que soporte los modos de escritura y lectura, a la vez.
  • Admite acceso multiusuario: Si bien requiere que se establezcan zonas especificas y limitadas para que los distintos accesos estén controlados, y no se pisen unos a otros, este tipo de acceso permite que varios usuarios trabajen sobre el fichero de manera simultánea.
  • Dimensionamiento máximo del fichero: Al trabajar con una estructura de longitud fija de registros, lo habitual es fijar el número máximo de registros que puede almacenar el fichero, y de este modo definir el tamaño máximo que podrá ocupar en memoria, y reservar dicho espacio en la misma.

Soporte físico

El soporte físico para este tipo de ficheros es el disco duro, ya no podemos almacenar la información en cintas magnéticas, ya que estas no admiten físicamente el acceso aleatorio, y debido a su propio funcionamiento te fuerzan a un acceso secuencial.

Ejemplo de archivo de acceso aleatorio

Después de explicar como funcionan los archivos de acceso aleatorio, para entenderlo mejor, os propongo un ejemplo, un caso práctico: vamos a ayudar a Antonio a mejorar su productividad en su tienda SuperGades. El problema que tiene es que su fichero de proveedores, que es un fichero de acceso secuencial, tiene ya 1.000 registros, y cada vez que busca los datos de un proveedor tarda de media 1 minuto. Recordemos que todavía estamos en el siglo pasado y no contamos con mucha capacidad de almacenamiento ni de computación, otro gallo nos cantará cuando SuperGades halla crecido y evolucionado y estemos utilizando el Big Data.

Antonio sabe que ganaría mucho tiempo si obtuviera los datos del proveedor en no más de 5 segundos, y alguien le ha explicado que puede conseguirlo si migra todos sus datos a un archivo de acceso aleatorio.

Os propongo el siguiente ejercicio para recorrer el camino con Antonio y entender como funcionan los archivos de acceso aleatorio.

Paso 1: Fichero secuencial de partida.

El fichero de proveedores de Antonio era:

Frutas Gutierrez

Antonio Gutierrez

607454545

<FIN>

Hortalizas del Sur

Guillermo Morales

652854874

<FIN>

Azucarera Sevillana

Rodrigo Mendez

622525885

<FIN>

Como este fichero ha crecido hasta 1.000 proveedores, vamos a trabajar con una versión “reducida” para hacerlo operativo.

Supongamos que ahora nuestro fichero es:

Frutas Gutierrez

Antonio Gutierrez

607454545

<FIN>

Hortalizas del Sur

Guillermo Morales

652854874

<FIN>

Azucarera Sevillana

Rodrigo Mendez

622525885

<FIN>

….

…..

…..

Huevos La Puebla

Araceli Arnedo

652879137

<FIN>

….

….

….

Arroces La Cigala

Maria Alvarez

677889922

<FIN>

Donde los puntos supensivos indican un espacio en el que habría varios registros, en total tendríamos 1.000

Paso 2: Definiendo la estructura de registro:

Como habíamos visto, para poder implementar el acceso aleatorio, la longitud de los registros tenía que ser fija. Para definir la longitud de un registro, tenemos que definir las longitudes de sus campos.

Para nuestro fichero, podemos asumir que vamos a trabajar con caracteres ANSI, de esta manera cada carácter ocupará un byte.

Definimos la longitud en caracteres/ bytes de los distintos campos:

  • 1 campo: 30 bytes (nombre del proveedor)
  • 2 campo: 30 bytes (nombre del contacto en el proveedor)
  • 3 campo: 9 bytes (número de teléfono del contacto)
  • 4 campo: 0 bytes . Eliminamos la marca de fin de registro, ya que esta la usábamos realmente en un fichero de acceso secuencial para sincronismo. Ahora, con el acceso aleatorio, no vamos a usarla, sino que nos colocaremos en el inicio del registro que queramos leer, y leemos tantos caracteres como la longitud del registro, en nuestro caso, 69.

De manera visual, representándolo únicamente para el primer registro, sería algo así:

Estructura de registro del fichero de acceso aleatorio

Observamos que en aquellos campos en los que no estoy seguro de la longitud que tendrán los datos, los definimos con cierto margen, por lo que en la mayoría de los casos estaremos infrautilizando la memoria, reservando espacio para datos que realmente no necesitamos. No obstante hay que hacerlo de esta manera porque queremos asegurar que se pueden registrar los datos más largos que podamos tener.

Paso 3: Paso del fichero de acceso secuencial al fichero de acceso aleatorio:

Definidas las longitudes de los campos, Antonio tendría que pasar todos los datos de proveedores a la nueva estructura de datos. Esto obviamente no se haría de forma manual, contaría para ello con un programa que realizaría esta tarea.

Paso 4: Accediendo a un registro completo:

Si quisiéramos acceder al registro 777, nos colocaríamos en la posición 53.545 y leeríamos 69 bytes.

¿Cómo calculamos la dirección?. Sencillamente multiplicamos 69 bytes que ocupa cada registro por 776, lo que nos da un valor de 53.544 bytes. El registro 777 empezaría justo en el byte siguiente.

Paso 5: Comparativa aproximada de tiempos:

En un fichero secuencial, para llegar al registro 777, tendríamos que leer todos los registros anteriores. Si bien, los registros serían más cortos, ya que no se reserva espacio extra en memoria que no se rellene con datos.

Supongamos que la media de la longitud del registro es de 50 bytes frente a los 69 bytes de longitud del registro del archivo de acceso aleatorio. Y que además, el tiempo de lectura de un carácter es de 1 milisegundo. Para cuando llegáramos al registro 777, habríamos leído: 50*776 = 38.800 caracteres, lo que nos hubiera llevado casi 39 segundos. Un tiempo de espera extremadamente alto.

Por el contrario, con el acceso aleatorio, sabiendo donde tenemos que posicionar el lector, es cuestión de milisegundos, es decir, prácticamente percibido por el usuario como inmediato.

Aquí es donde Antonio consigue una mejora de la productividad por la reducción considerable de los tiempos de espera.

Paso 6: Experimentándolo:

Creamos una base de datos nueva, le ponemos el nombre que queramos, por ejemplo: BBDD2

Paso 7: Creamos un modulo nuevo

Vamos a la pestaña “HERRAMIENTAS DE BASE DE DATOS” , pulsamos en “Visual Basic”.

A continuación, en el menú Inserta/Modulo, creamos un nuevo módulo. En mi caso, lo dejo con el nombre por defecto: “Módulo1”, ya que sólo lo vamos a usar para practicar.

Paso 8: Programamos un procedimiento para crear el archivo de acceso secuencial de partida

Lo primero que haremos será crear un archivo con los datos. Crearemos los proveedores que indicaba en pasos anteriores, y rellenaremos el resto de posiciones con nombres de proveedores genéricos, al final tendremos un fichero con 1.000 registros.

El procedimiento que realizaría esta tarea sería:

Sub CrearArchivoSecuencial()

Dim i As Integer

Dim prov As String

Dim cont As String

On Error GoTo e

ChDrive («D»)

ChDir «D:\pruebas»

‘Instrucción Open: https://docs.microsoft.com/es-es/office/vba/language/reference/user-interface-help/open-statement

Open «Proveedores.txt» For Output As #1

‘Registro de proveedores

Print #1, «Frutas Gutierrez»

Print #1, «Antonio Gutierrez»

Print #1, «607454545»

Print #1, «<FIN>»

Print #1, «Hortalizas del Sur»

Print #1, «Guillermo Morales»

Print #1, «652854874»

Print #1, «<FIN>»

Print #1, «Azucarera Sevillana»

Print #1, «Rodrigo Mendez»

Print #1, «622525885»

Print #1, «<FIN>»

For i = 4 To 766

prov = «Provedor nº» & i

cont = «Contacto de Proveedor nº» & i

Print #1, prov

Print #1, cont

Print #1, «xxxxxxxxx»

Print #1, «<FIN>»

Next

Print #1, «Huevos La Puebla»

Print #1, «Araceli Arnedo»

Print #1, «652879137»

Print #1, «<FIN>»

For i = 778 To 1000

prov = «Provedor nº» & i

cont = «Contacto de Proveedor nº» & i

Print #1, prov

Print #1, cont

Print #1, «xxxxxxxxx»

Print #1, «<FIN>»

Next

‘Cerrar el archivo:

Close #1

MsgBox («Guardados 1000 registros de proveedores»)

Exit Sub

e:

MsgBox (Err.Description)

End Sub

Paso 9: Definimos la estructura que tendría nuestro fichero de acceso aleatorio

Ya la habíamos definido en el paso 2. Asumiendo que cada carácter ocupa un byte, teníamos:

  • 1 campo: 30 bytes (nombre del proveedor)
  • 2 campo: 30 bytes (nombre del contacto en el proveedor)
  • 3 campo: 9 bytes (número de teléfono del contacto)
  • 4 campo: 0 bytes . Eliminamos la marca de fin de registro, ya que esta la usábamos realmente en un fichero de acceso secuencial para sincronismo. Ahora, con el acceso aleatorio, no vamos a usarla, sino que nos colocaremos en el inicio del registro que queramos leer, y leemos tantos caracteres como la longitud del registro, en nuestro caso, 69.

Paso 10: Transformamos nuestro fichero de proveedores a la nueva estructura fija

Tenemos que recorrer el fichero de proveedores y extender los datos en los distintos campos para que ocupen la longitud fijada en la nueva estructura. Para hacerlo visible rellenare los espacios añadidos con un punto “.” .

Para ello usaremos el siguiente procedimiento:

Sub PasarSecuencial_Aleatorio()

 ChDrive («D»)

ChDir «D:\pruebas»

 Dim linea As String

Dim escribir As String

Dim MyChar As String

Dim tipoRegistro As Integer

Dim i As Integer

Dim j As Integer

 Open «Proveedores.txt» For Input As #1

Open «ProvAccesoAleatorio.txt» For Output As #2

 linea = «»

tipoRegistro = 1

 Do While Not EOF(1)

    MyChar = Input(1, #1)

    If MyChar = Chr(13) Then

        If tipoRegistro = 4 Then

            tipoRegistro = 1

            linea = «»

        Else

            Select Case (tipoRegistro)

                Case 1

                    escribir = linea

                    j = Len(linea)

                    For i = j To 30

                        escribir = escribir & «.»

                    Next i

                    Debug.Print escribir

                    Print #2, escribir

                    linea = «»

                Case 2

                    escribir = linea

                    j = Len(linea)

                    For i = j To 30

                        escribir = escribir & «.»

                    Next i

                    Debug.Print escribir

                    Print #2, escribir

                    linea = «»

                Case 3

                    escribir = linea

                    j = Len(linea)

                    For i = j To 9

                        escribir = escribir & «.»

                    Next i

                    Debug.Print escribir

                    Print #2, escribir

                    linea = «»

            End Select

            tipoRegistro = tipoRegistro + 1

        End If

    ElseIf (MyChar <> Chr(10)) Then

        linea = linea + MyChar

    Else

    End If

Loop

Close #1

Close #2

End Sub

 Paso 11: Reduciendo el tamaño del fichero

Para trabajar con el fichero en la práctica, vamos a reducir el número de proveedores a 20. El objetivo es poder trabajar con variables enteras, sin tener que irnos a manejar grandes números, y no tener problemas de desbordamiento.

Paso 12: Desplazándonos directamente a un número de registro

Tenemos que primero calcular la posición en la que empezaría el registro, y a continuación movernos hasta ella y leer una cantidad determinada de datos. Todo sometido a una estricta estructura.

Para realizarlo, usamos el siguiente procedimiento:

Sub IrRegistro()

ChDrive («D»)

ChDir «D:\pruebas»

Dim NumeroRegistro As Integer

Dim posicion As Integer

Dim contador As Integer

Dim MyChar As String

Dim i As Integer

Dim texto As String

Open «ProvAccesoAleatorio.txt» For Input As #1

NumeroRegistro = CInt(InputBox(«Introduce numero de registro. Asegurate que este entre 1 y 1000», «Buscar registro por su número»))

posicion = (30 + 30 + 10 + 8) * (NumeroRegistro – 1)

posicion = posicion + 1

contador = 0

texto = «»

 Do While Not EOF(1)

    MyChar = Input(1, #1)

    contador = contador + 1

    If posicion = contador Then

    For i = posicion To (posicion + 75)

        texto = texto + MyChar

        MyChar = Input(1, #1)

    Next i

    Debug.Print texto

    Exit Do

    End If

Loop

Close #1

End Sub

NOTA:

Este post es parte de la colección “Arquitectura de Datos” que reproduce los apuntes de la clase que imparto sobre el tema en ESIC. Puedes ver el índice de esta colección aquí.