7.2. Ficheros con tipo
Curso: Programación en Pascal (v5), por Nacho Cabanes
7.2. Ficheros con tipo.
Hemos visto cómo acceder a los ficheros de texto, tanto para leerlos como para escribir en ellos. Ahora nos centraremos en lo que vamos a llamar " ficheros con tipo".
Estos son ficheros en los que cada uno de los elementos que lo integran es del mismo tipo (como vimos que ocurre en un array).
En los de texto se podría considerar que estaban formados por elementos iguales, de tipo "char", pero es un dato demasiado pequeño, de modo que los leíamos y escribíamos línea a línea.
Ahora vamos a llegar más allá, porque un fichero formado por datos de tipo "record" sería lo ideal para una agenda o cualquier otra colección de datos estructurados.
Conociendo los ficheros de texto, no hay muchas diferencias a la hora de un primer manejo de ficheros con tipo: debemos declarar un fichero, asignarlo, abrirlo, trabajar con él y cerrarlo.
Pero ahora también podemos hacer más cosas, que con un fichero de texto no era posible. En aquellos, el uso habitual era leer línea por línea, no carácter por carácter. Como las líneas pueden tener cualquier longitud, no podíamos empezar por leer la línea 4 (por ejemplo), sin haber leído antes las tres anteriores, porque no sabríamos en qué posición del fichero empezará esa línea 4. Esto se conoce como
acceso secuencial
: para llegar a un punto debemos recorrer primero las partes anteriores del fichero.Por el contrario, en un "fichero con tipo", sí que sabemos lo que va a ocupar cada dato, ya que todos son del mismo tipo, y podremos aprovecharlo para acceder a una determinada posición del fichero cuando nos interese, sin necesidad de pasar por todas las posiciones anteriores. Esto es el acceso aleatorio (o "acceso directo"). La idea es sencilla: si cada ficha ocupa 25 bytes, y queremos leer la número 8, bastaría con "saltarnos" 25*7=175 bytes.
Pero algunos compiladores recientes (como Turbo Pascal y Free Pascal) nos lo facilitan más aún, con una orden, seek, que permite saltar a una cierta "ficha" (un "record") dentro del fichero, sin necesidad de calcular nada nosotros mismos.
Vamos a comenzar por introducir varias fichas en un fichero con tipo. Las únicas diferencias con lo que conocemos son que el tipo del fichero no será "text" sino "file of TipoBase" y que escribiremos con "write", en vez de "writeLn":
(* CREAFT.PAS, Crea un fichero "con tipo" *) (* Parte de CUPAS5, por Nacho Cabanes *) program CreaFT; type ficha = record (* Nuestras fichas *) nombre: string [80]; edad: byte end; var fichero: file of ficha; (* Nuestro fichero *) numFicha: byte; (* Para bucles *) datoActual: ficha; (* La ficha actual *) begin assign( fichero, 'ejemplo.dat' ); (* Asignamos *) rewrite( fichero ); (* Abrimos (escritura) *) writeLn('Te ire pidiendo los datos de cuatro personas...' ); for numFicha := 1 to 4 do (* Repetimos 4 veces: *) begin (* Pedimos un dato *) writeLn('Introduce el nombre de la persona numero ', numFicha); readln( datoActual.nombre ); writeLn('Introduce la edad de la persona numero ', numFicha); readln( datoActual.edad ); write( fichero, datoActual ); (* Guardamos el dato *) end; close( fichero ); (* Cerramos el fichero *) end.
Si queremos leer sólo la tercera ficha de este fichero de datos que acabamos de crear, usaríamos "seek". La posición de las fichas dentro de un fichero de empieza a numerar en 0, que corresponderá a la primera posición. Así, accederemos a la segunda posición con un 1, a la tercera con un 2, y en general a la "n" con "seek(fichero,n-1)":
(* LEEFT.PAS, Lee un dato de un fichero "con tipo" *) (* Parte de CUPAS5, por Nacho Cabanes *) program LeeFt; type ficha = record nombre: string [80]; edad: byte end; var fichero: file of ficha; datoActual: ficha; begin assign( fichero, 'ejemplo.dat' ); reset( fichero ); (* Abrimos (lectura) *) seek( fichero, 2 ); (* <== Vamos a la ficha 3 *) read( fichero, datoActual ); (* Leemos *) writeLn('El tercer nombre es: ', datoActual.nombre ); writeLn('Su edad es: ',datoActual.edad ); close( fichero ); (* Y cerramos el fichero *) end.
Por supuesto, también podemos leer un fichero con tipo hasta el final. La diferencia con un fichero de texto es que ahora no podemos usar "while not eof", pero la alternativa es comprobar el tamaño usando "filesize", de modo que podremos leer "hacia delante" con "read" (y usar un contador con un "for"), o bien también saltar a cualquier otra posición con "seek":
(* LEEFT2.PAS, Lee todo un fichero "con tipo" *) (* Parte de CUPAS5, por Nacho Cabanes *) program LeeFt2; type ficha = record nombre: string [80]; edad: byte end; var fichero: file of ficha; datoActual: ficha; tamanyo: longint; numFicha: integer; begin assign( fichero, 'ejemplo.dat' ); reset( fichero ); tamanyo := filesize( fichero ); for numFicha := 1 to tamanyo do begin read( fichero, datoActual ); writeLn('Ficha actual: ', numFicha ); writeLn('Nombre: ', datoActual.nombre ); writeLn('Edad: ',datoActual.edad ); writeLn; end; close( fichero ); end.
Ejercicio propuesto 7.2.1: Crea un programa que pida al usuario los nombres de los 12 meses y la cantidad de días de cada mes, almacene cada uno de esos pares de datos en un "record" y los guarde en un "fichero con tipo" llamado "meses.dat".
Ejercicio propuesto 7.2.2: Crea un programa que lea el fichero "meses.dat" como si fuera un fichero de texto y muestre en pantalla lo que va leyendo. Comprobarás que no se comportará correctamente, aunque hayas guardado "sólo" textos y números en el fichero.
Ejercicio propuesto 7.2.3: Crea un programa que lea y muestre el fichero "meses.dat" como "fichero con tipo", usando la construcción "while not eof".
Ejercicio propuesto 7.2.4: Crea un programa que lea y muestre el fichero "meses.dat" como "fichero con tipo", usando "filesize" y un bucle "for".
Ejercicio propuesto 7.2.5: Crea un programa que pida al usuario el número de un mes, de 1 (enero) a 12 (diciembre) y muestre el nombre de ese mes y la cantidad de días que contiene, usando "seek" en el fichero "meses.dat".
Ejercicio propuesto 7.2.6: Crea un programa que lea y muestre el fichero "meses.dat" en orden inverso (del último mes al primero), usando "filesize", "seek" y un bucle "for".
Actualizado el: 21-07-2014 00:23