TEMA 4: Manejo de Archivos Dentro de este apartado vamos a aprender que son y como utilizar los archivos. Veremos cual es su finalidad, que tipos son los más comunes y cuales son sus características principales desde el punto de vista de la organización de los datos que contiene. Para comenzar podemos decir que un ordenador que no tiene la posibilidad de almacenar sus programas y datos en un dispositivo de almacenamiento, (ya sean discos, cintas, etc.) no es mas que una calculadora. En la actualidad, cualquier ordenador posee dispositivos de almacenamiento, ya sean internos (discos duros) o externos (disquetes, cartuchos, cintas, etc.). La finalidad es obvia, la de poder guardar los datos para su posterior recuperación y tratamientos de los mismos en otras sesiones. Un común error entre los principiantes es el de confundir la memoria de tipo RAM con la capacidad de almacenamiento del disco que acompaña al ordenador. La RAM (Memoria de Acceso Aleatorio) es denominada memoria volátil, ya que una vez que se apaga el ordenador la información que esta contenía se pierde. La RAM se mide generalmente en MegaBytes, aunque con el paso del tiempo la unidad puede cambiar (1 Mb son 1024 Ks, a su vez 1 K es 1024 bytes, y finalmente 1 Byte son 8 bits, siendo esta última la cantidad mínima de información que puede procesar un computador). La capacidad de los dispositivos de almacenamiento (entiéndase disquetes, discos duros, cintas, CD-ROM, etc.) se mide en las mismas unidades, es por ello que la gente suele confundir la memoria RAM de un ordenador con la capacidad de almacenamiento que suele tener en un disco duro. La memoria RAM es uno de los aspectos que limita la potencia de un ordenador, cuanta más RAM tengamos, mayores programas y datos podremos almacenar en ella y menos accesos a los dispositivos de almacenamiento tendremos que realizar. Los archivos o ficheros se almacenan en los dispositivos de almacenamiento, para como dijimos anteriormente puedan ser recuperados sus datos en sesiones futuras. De esta forma, podemos definir un fichero como un objeto concebido para el almacenamiento permanente de la información. Información que puede ser organizada de diferente forma dependiendo del trato que le vayamos a dar. 4.1 Nociones de dispositivos de almacenamiento. En el apartado anterior hemos aprendido que la información puede ser volcada en dispositivos de almacenamiento permanente, a los cuales nos hemos referido como disquetes, discos duros, cintas, CD-ROM, etc. Estos medios de almacenamiento se pueden diferenciar en el modo en el que la información puede ser accesible. Así definimos dispositivos de almacenamiento o soportes secuenciales a aquellos donde la información es accesible secuencialmente, es decir, para leer o escribir un dato determinado, antes tenemos que pasar por todos los datos que le preceden. De esta forma, en una cinta magnética los datos se graban y leen uno detrás de otro. Y no podemos ir directamente a uno en concreto sin pasar antes por los demás. De igual forma se define soportes direccionables a aquellos donde la superficie de almacenamiento es independiente e individualmente direccionable, es decir, podemos acceder a un dato en concreto sin tener que pasar antes por los demás. Este es el caso de los discos. Por poner un ejemplo, en un disco de vinilo, podemos elegir la canción que queremos tan sólo con poner el cabezal en el comienzo de la misma. Sin embargo, en una cinta de casete, para oír una canción determinada antes debemos pasar todas las que le preceden. En los dispositivos de almacenamientos hay que diferenciar las direcciones en las que se almacenan los datos. De este modo tenemos dos tipos de direcciones: direcciones absolutas o físicas y direcciones relativas o lógicas. Las direcciones absolutas o físicas son las direcciones con las que juega el ordenador de forma física en el dispositivo, es decir, cuando el ordenador se refiere a un dato en concreto lo esta haciendo por el conocimiento de ciertos datos que identifican la posición física del dato en el soporte de almacenamiento. Así, el ordenador juega con parámetros tales como: unidad, cabeza, cara, pista o cilindro y sector. Por el contrario, las direcciones relativas o lógicas son con las que vamos a jugar nosotros, una vez que abrimos el fichero para realizar operaciones de Input/output (I/O) nos referimos al dato con un índice numérico, es decir, el registro número x. 4.2 Ficheros de Acceso Secuencial. Un Fichero de Acceso Secuencial es aquel donde los registros están ubicados consecutivamente sobre un dispositivo de almacenamiento. De tal forma que para acceder a un registro determinado 'd' debemos pasar obligatoriamente por todos los registros que le preceden. Suponiendo una cinta magnética, para leer registro 'd' debemos pasar antes por el 'a', 'b', 'c'. ---------------------- Para leer el registro 'd', la cabeza +- a b c d ... lectora, deberá pasar antes por los | ---------------------- que le preceden. +> cabeza lectora. Un Fichero de Acceso Secuencial puede ser almacenado tanto en un dispositivo de almacenamiento direccional como secuencial, sin embargo los Ficheros de Acceso Directo e Indexado únicamente puede ubicarse en dispositivos de almacenamiento direccional. 4.2.1 Ejemplo de I/O en Ficheros Secuenciales. Pasemos a ver un ejemplo de como utilizar ficheros secuenciales, pero antes veamos las sentencias básicas que utilizaremos. - Abrir secuencial (variable) Esta sentencia abre un fichero para el acceso secuencial. Donde la variable contiene el nombre del fichero a abrir. - Cerrar (variable) Esta sentencia cierra un fichero donde la variable contiene el nombre del fichero a cerrar. - Leer/Escribir/Reescribir (variable1,variable2) Esta sentencia permite la lectura o re/escritura de los datos que contiene la variable2 en un fichero de nombre, el determinado en la variable1. - Iniciar operaciones de lectura y/o escritura en (variable) Esta sentencia debe incluirse después de abrir un fichero y determina prácticamente el tipo de acceso que vamos a realizar, es decir, si abrimos el fichero para leer y/o escribir. - NO fin (variable) Esta función devuelve el valor lógico 'true' si no se ha encontrado el final del fichero; y devuelve el valor lógico 'false' si se ha encontrado el final del fichero. - Error (variable) Esta función devuelve el código del error producido al realizar cualquier operación anterior. Por defecto, la función devuelve un cero cuando no se ha producido ningún error. Ejemplo: En este ejemplo se intenta dar aun visión general del uso de ficheros secuenciales. +-Algoritmo Copiar_fichero | | Fichero de enteros Origen,Destino | Variable entera x | | Escribir ("Indique el nombre del fichero Origen:"); | Leer Origen | Escribir ("Indique el nombre del fichero Destino:") | Leer Destino | | Abrir secuencial (Origen) | Iniciar lectura en (Origen) | Abrir secuencial (Destino) | Iniciar escritura en (Destino) | | +-Mientras (NO fin(Origen)) hacer | | Leer (Origen,x) | | Escribir (Destino,x) | +-Finmientras | | Escribir ("Fichero Copiado:") | | Cerrar (Origen) | Cerrar (Destino) | +-Final Nota: Obsérvese que la variable utilizada en las operaciones de lectura y/o escritura, deben ser del mismo tipo que la declaración del fichero. 4.3 Registros Estructurados. Hasta ahora hemos visto como los registros eran de un tipo único, es decir, eran todos carácter, enteros, reales, etc. Sin embargo, hay situaciones en las que debemos realizar agrupaciones de tipos para formar un registro estructurado. Así, un registro estructurado esta formado por un conjunto de variables de diferentes tipos que denominaremos campos. De este modo podemos decir que un registro estructurado es un conjunto de campos. Ejemplo: +-Registro datos-alumno | Cadena nombre | Cadena apellido1 | Cadena apellido2 | Cadena NIF | Cadena curso | Cadena telefono | Cadena fecha_nac | ... +-Finregistro De esta forma, podemos leer y escribir en un fichero registros estructurados que nos permitirán un almacenamiento más lógico y ordenado de los datos. Al generar un registro es como si estuviésemos definiendo un nuevo tipo de variable independiente de las ya existente (enteras, reales, cadena, etc.). Este tipo de registros o record se utiliza para agrupar la información que se desee volcar a un fichero determinado. 4.4 Ficheros de Acceso Directo. Un Fichero de Acceso Directo (es también denominado de acceso aleatorio) es aquel que se encuentra almacenado en un dispositivo direccionable; y donde sus registros poseen un campo que denominaremos campo clave y que identifica inequívocamente a cada registro. En los ficheros de acceso directo el campo clave es el número del registro en el fichero. Así se establece una correspondencia directa entre los valores del campo clave y las direcciones lógicas en el soporte. Los registros se almacenan según el orden de entrada y no quedan ordenados. De esta forma en un Fichero de Acceso Directo nos referimos a un registro por medio de su posición en este. Así, podremos obtener el reg número 4 sin pasar antes por los demás. +-----+------------+ | Reg | D A T O | +-----+------------| Fíjese que los datos están | 1 | LUIS | almacenados en el orden en el | 2 | CARLOS | que han sido introducidos por el | 3 | TERESA | usuario. | 4 | JOAQUIN | | 5 | INMA | Accedemos a los datos por medio | 6 | JOSE | del valor de la posición del +-----+------------+ registro. La tabla anterior se denomina tabla de acceso. Esta tabla relaciona de forma única el número del registro con el registro correspondiente, así el reg número 2 corresponde al dato Carlos. 4.4.1 Ejemplo de I/O en Ficheros de Acceso Directo. Las sentencias que manejan los ficheros de acceso directo son las mismas, sólo que poseen el prefijo directo. Ejemplo: +-Algoritmo Contador_de_registros. | | Fichero de enteros F | Variable entera x,contador | | Abrir directo (F) | Iniciar lectura (F) | contador = 0 | +-Mientras (NO fin(F)) hacer | | Leer directo(F,x) | | contador=contador+1 | +-Finmientras | Cerrar(F) | | Escribir ("El fichero:";F;"posee:";contador;"reg.") | +-Final 4.5 Ficheros de Acceso Indexado. Un Fichero de Acceso Indexado es aquel que se encuentra almacenado en un dispositivo direccionable; y donde sus registros poseen un campo que denominaremos campo clave principal y que identifica inequívocamente a cada registro. La clave principal debe ser aquel campo del registro estructurado que tenga siempre un valor diferente a los ya introducidos, es decir, dentro del fichero Indexado no puede haber dos registros con los campos clave principal iguales. Además del campo clave principal pueden existir otros campos claves secundarios que realizan la misma tarea que el campo clave, sin embargo, sus valores pueden repetirse. En los Ficheros de Acceso Indexado el campo clave puede ser cualquiera de los campos de un registro estructurado. Así se establece una correspondencia directa entre los valores del campo clave y el propio registro al que pertenece. Los registros se almacenan ordenados alfabéticamente por el campo clave, esto nos facilita la búsqueda y listados ordenados por los distintas claves. Para cada campo clave, el fichero genera una tabla, donde dicha clave aparece ordenada alfabéticamente y se relaciona con la dirección de los datos. De esta forma en un Fichero de Acceso Indexado nos referimos a un registro por medio de alguna de las claves que posea el fichero, tanto la principal como la secundaria. Es decir, leer el registro cuya clave principal sea: 46.399.554, en este caso leería el registro correspondiente a INMA. También podríamos haber dicho, leer los registro cuya clave secundaria sea la Edad=16 y primero nos leería el registro correspondiente a los datos de Luis y en la siguiente petición de lectura los datos de Teresa. La diferencia entre clave principal y secundaria, está en que la clave principal es única (relacionando así inequívocamente al registro al que pertenece) mientras que las claves principales puede ser iguales. +------------+-------------------------------------+ | Clave | Clave Clave Clave | | Principal | Secundaria Secundaria Secundaria | +--------------------------------------------------+ +---------+------------+------------+-------------+--------+ | (Direc) | (D.N.I.) | (Nombre) | (Provincia) | (Edad) | +---------|------------|------------|-------------|--------+ | 1 | 55.366.546 | LUIS | Las Palmas | 16 | | 2 | 42.386.225 | CARLOS | Salamanca | 17 | | 3 | 32.387.203 | TERESA | Oviedo | 16 | | 4 | 46.399.554 | INMA | Palencia | 20 | | 5 | 60.643.434 | JOAQUIN | Salamanca | 17 | | 6 | 22.543.986 | JOSE | Las Palmas | 23 | +---------+------------+------------+-------------+--------+ Como podemos observar, esto sería un ejemplo de un fichero indexado. Para cada campo clave, el fichero genera una tabla, donde dicha clave aparece ordenada alfabéticamente y se relaciona con la dirección de los datos. Así las tablas para la clave principal (DNI) y la clave secundaria (Nombre) serían: +------------+---------+ +------------+---------+ | (D.N.I.) | (Direc) | | (Nombre) | (Direc) | +------------+---------| +------------+---------+ | 22.543.986 | 6 | | CARLOS | 2 | | 32.387.203 | 3 | | INMA | 4 | | 42.386.225 | 2 | | JOAQUIN | 5 | | 46.399.554 | 4 | | JOSE | 6 | | 55.366.546 | 1 | | LUIS | 1 | | 60.643.434 | 6 | | TERESA | 3 | +------------+---------+ +------------+---------+ +--------------------------+ +---------------------------+ | Tabla de Ac. Clave Princ.| | Tabla de Ac. Clave Secund.| +--------------------------+ +---------------------------+ Obsérvese como ambas tablas aparecen ordenadas alfabéticamente (o de menor a mayor en el caso del DNI). Como ya dijimos, esto nos da grandes facilidades a la hora de realizar búsquedas y/o listados ordenados. 4.5.1 Ejemplo de I/O en Ficheros de Acceso Indexado. Pasemos a ver un ejemplo de como utilizar ficheros indexados, pero antes veamos las sentencias básicas que utilizaremos. - Abrir indexado (variable,KEY=...) Esta sentencia abre un fichero para el acceso indexado. Donde la variable contiene el nombre del fichero a abrir y en 'KEY=' ponemos los campos claves separados por comas, comenzando por el campo clave principal. - Cerrar (variable) Esta sentencia cierra un fichero donde la variable contiene el nombre del fichero a cerrar. - Leer/Escribir/Reescribir (variable1,KEY=,variable2) Esta sentencia permite la lectura o re/escritura de los datos por medio de un campo clave (principal o secundaria) que debemos poner después de 'KEY='. El contenido será almacenado o mandado por la variable2 en un fichero de nombre, el determinado en la variable1. - Iniciar operaciones de lectura y/o escritura en (variable) Esta sentencia debe incluirse después de abrir un fichero y determina prácticamente el tipo de acceso que vamos a realizar, es decir, si abrimos el fichero para leer y/o escribir. - NO fin (variable) Esta función devuelve el valor lógico 'true' si no se ha encontrado el final del fichero; y devuelve el valor lógico 'false' si se ha encontrado el final del fichero. - Error (variable) Esta función devuelve el código del error producido al realizar cualquier operación anterior. Por defecto, la función devuelve un cero cuando no se ha producido ningún error. Las sentencias que manejan los ficheros de acceso Indexado son las mismas que hemos utilizado en los ficheros secuenciales, sólo que poseen el prefijo Indexado y en las operaciones de lectura y/o escrituras hay que indicar la clave ('KEY='). Ejemplo: +-Algoritmo Buscar_Persona. | | +-Registro estructurado datos_personales | | Variable cadena dni | | Variable cadena nombre | | Variable cadena tlf | | Variable cadena provincia | +-Finregistro | | Fichero de datos_personales F | Variable cadena documento | Variable de datos_personales dato | | Escribir "Indique el DNI de la persona a buscar" | Leer documento | | Abrir indexado (F,KEY=dni,nombre) | Iniciar lectura (F) | | Leer (F,KEY=documento,dato) | +-Si error(F)<>0 entonces | | Escribir "Ese registro no existe." | +-Sino | | Escribir " DNI: ";dato.dni | | Escribir " Nombre: ";dato.nombre | | Escribir " Tlf: ";dato.tlf | | Escribir "Provincia: ";dato.provincia | +-Finsi | | Cerrar (F) +-Final 4.6 Función de Hashing. Muchas veces surge el caso del que el fichero es tan grande que la tabla no puede mantener una ordenación eficaz debido a que cuando introducimos un nuevo dato debe hacerse un espacio en la misma para albergar a éste. Es por ello que recurrimos al "Hashing". El "Hashing" consiste simplemente en relacionar la clave principal con la dirección por medio de una fórmula matemática. Así, antes de introducir datos se crean unos espacios para albergar las futuras modificaciones y adiciones de datos. Este método crea una serie de conjuntos llamados "Buckets". A cada Bucket le corresponde un número que será el que devuelva la fórmula matemática. A su vez los Buckets poseen un número que determina la cantidad máxima de claves que pueden almacenarse en él. De esta manera cuando vamos a buscar el dato "Manolo" el Hashing nos determina la posición del conjunto (Buckets). En ese conjunto habrá otra serie de datos a los cuales les corresponde el mismo valor de la función Hashing. La búsqueda ahora se hará de forma secuencial a lo largo del Bucket. Veamos un ejemplo: Bucket Clave Prin. Claves Secundarias +-----+------------+----------------------+ | | Manolo | . . . | | +------------+----------------------+ | 35 | Manuel | . . . | Al número 104 +-----+------------+----------------------+ se le denomina +--| 104 | Manuela | . . . | puntero de | +-----+------------+----------------------+ desbordamiento | | | Natalia | . . . | | | +------------+----------------------+ | | 36 | Naranjo | . . . | | | +------------+----------------------+ | | | Noelia | . . . | | +-----+------------+----------------------+ | . | . | . | +-----+------------+----------------------+ | | | Mark | . . . | | | +------------+----------------------+ +->| 104 | Miguel | . . . | | +------------+----------------------+ | | María | . . . | +-----+------------+----------------------+ 4.6.1 Gestión de las colisiones. En este método parecen una serie de conflictos cuando las claves son muy parecidas, como podemos observar para claves casi idénticas, el Hashing nos devuelve el mismo Bucket. Esto implica que el Bucket puede llenarse de datos; cuando esto ocurre la solución está en un puntero que existe en cada Bucket que determina el salto a otro Bucket. Así, cuando se llena el Bucket número 35, existe un salto de éste al número 104 (otro Bucket) que posee datos del mismo tipo, que también puede rebosarse y apuntar a otro Bucket secundario y así sucesivamente. Ahora es cuando surgen los problemas. Cuando un dato se borra de un Bucket hay que reorganizar la información para no dejar espacios en blanco dentro de la tabla. Esto se realiza por medio de un empaquetamiento Packed. Sin embargo cuando se va a realizar muchas modificaciones y/o borrados y el fichero es muy grande, es aconsejable hacer una actualización de los datos del fichero. 4.7 Esquema Básico de los tres tipos de Organización. * Fichero de Acceso Secuencial: - Almacenamiento en dispositivo secuencial o direccionable. - No existe campos claves que relacione a algún registro. - Los datos están almacenados en el orden en el que han sido introducidos. - El acceso a los registros es únicamente secuencial. * Fichero de Acceso Directo: - Almacenamiento en dispositivo direccionable. - Existe en los registros un campo denominado campo clave que hace referencia inequívoca a dicho registro a través del número de registro. - Los datos están almacenados en el orden en el que han sido introducidos. - El acceso a los registros puede ser tanto aleatorio a través del campo clave como secuencial. * Fichero de Acceso Indexado: - Almacenamiento en dispositivo direccionable. - Existe en los registros un campo denominado campo clave principal y campo clave secundario, que hacen referencia inequívoca a dicho registro. - Los datos están almacenados en el orden alfabético por el campo clave. - El acceso a los registros puede ser tanto aleatorio a través del campo clave como secuencial. - El acceso Indexado-Secuencial permite el acceso como si se tratara de un fichero secuencial, sin embargo, los datos no saldrán en el orden en el que fueron introducidos sino en orden alfabético por el campo que estamos leyendo.