Documente Academic
Documente Profesional
Documente Cultură
Despus de la teora expuesta hasta ahora acerca del trabajo con ficheros, habr
observado que la metodologa de trabajo se repite.
- Abrimos un flujo desde el fichero del cual queremos leer los datos.
- Leemos los datos del ficheros y los almacenamos en variables de nuestro
programaron el fin de trabajar con ellos. Este proceso se hace normalmente
registro a registro. Para ello, utilizaremos los mtodos proporcionados por la
interfaz del flujo.
- Cerramos el flujo.
EJEMPLOS:
Escribir en un fichero:
try
{
//Crear un flujo hacia el fichero que permita escribir
//datos de tipos primitivos y que utilice un buffer.
dos = new DataOutputStream (new BufferedOutputStream(new
FileOutputstream(fichero)));
El mtodo expuesto anteriormente recibe como parmetro un objeto File que define el
nombre del dichero que se desea crear y realiza las tareas siguientes:
- Crea un flujo hacia el fichero especificado por el objeto File que permite
escribir datos de tipos primitivos utilizando un buffer.
EJEMPLO:
Leer de un fichero
Para leer de un fichero creado por la aplicacin anterior, vamos a escribir otra
aplicacin basada en una clase de MostrarListaTfnos. Esta clase definir dos mtodos;
try
{
//Crear un objeto File que identifique al fichero
fichero = new File (nombreFichero);
//Verificar si el fichero existe
if (fichero.exists())
{
//Si existe, abrir un flujo desde el mismo
dis = new DataInputStream (new BufferedInputStream( new
FileInputStream(fichero)));
//Declarar los datos a leer desde el fichero
String nombre, direccin;
long telfono;
do
{
//Leer un nombre, una direccin y un telfono desde el
//fichero
//Cuando se alcance el final del fichero Java lanzar una
//excepcin EOF, End Of File.
nombre = dis.readUTF();
direccion = dis.readUTF();
telefono = dis.readLong();
//Mostrar los datos nombre, direccion y telefono.
flujoS.println(nombre);
flujoS.println(direccion);
flujoS.println(telefono);
flujoS.println();
}
while (true);
}
else
{
flujoS.print("El fichero no existe");
}
}
catch (EOFException e)
{
flujoS.println ("Fin del listado");
}
finally
{
//Cerrar el flujo
if (dis != null)
dis.close();
}
}
Hasta este punto, hemos trabajado con ficheros de acuerdo con el siguiente esquema:
abrir el fichero, leer o escribir hasta el final del mismo, y cerrar el fichero. Pero no
hemos ledo o escrito a partir de una determinada posicin dentro del fichero. Esto esto
es particularmente importante cuando necesitamos modificar algunos de los valores
contenidos en el fichero o cuando necesitemos extraer una parte concreta dentro del
fichero.
La clase RandomAccessFile
Un flujo de esta clase permite acceder directamente a cualquier posicin dentro del
fichero vinculado con l.
El primer constructor abre un flujo vinculado con el fichero especificado por nombre-
fichero, mientras que el segundo hace lo mismo, pero a partir de un objeto File. El
argumento modo puede ser:
Por ejemplo, el siguiente fragmento de cdigo construye un objeto File para verificar si
el nombre especificado para el fichero existe como tal. Si existe y no corresponde a
unfichero se lanza una excepcin; si existe y se trata de un fichero, se crea un flujo para
escribir y leer a y desde ese fichero; y si no existe, tambin se crea el flujo y el fichero.
La sentencia throw permite a un mtodo lanzar una excepcin en funcin de los hechos
que hayan ocurrido. Dicha excepcin podr ser atrapada por el propio mtodo o por
algn otro que se encuentre en el retorno por la pila de llamadas; si no se encuentra un
mtodo que pueda atraparla, la aplicacin ser interrumpida.
- Este devuelve la posicin actual en bytes del puntero. Entienda puntero como
el ndice de una matriz y tenga siempre presente este puntero marca siempre
la posicin donde se iniciar la siguiente operacin de lectura o de escritura.
Segn lo expuesto, las dos lneas de cdigo siguientes sitan el puntero de R/W, la
primera desp bytes antes del final del fichero y la segunda desp bytes despus de la
posicin actual.
Igual que ocurra al trabajar con ficheros accedidos secuencialmente, los datos que
deseemos escribir en un fichero accedido aleatoriamente deben guardarse uno a uno
utilizando el mtodo adecuado de la clase del flujo vinculado. Por ejemplo, las
siguientes lneas de cdigo escriben en le fichero datos a partir de la posicin desp
dentro del mismo, los atributos nombre, direccin y telfono relativos a un objeto
CPersona:
CPersona objeto;
//..
RandomAccessFile ges = new RandomAccessFile ("datos", "rw");
fes.seek(desp);
fes.writeUTF(objeto.obtenerNombre());
fes.writeUTF(objeto.obtenerDireccion());
fes.writeLong(objeto.obtenerTelefono());
Como ejemplo supongamos que deseamos mantener una lista de telfonos. Cada
elemento de la lista ser un objeto persona con los atributos nombre, direccion y
telfono. A su vez, la lista de telfonos ser otro objeto que encapsule un flujo
vinculado con un fichero y muestre una interfaz que permita aadir, eliminar y buscar
una persona en la lista. Cada registro del fichero contendr los atributos nombre
direccin y telfono de cada uno de los objetos persona que forman la lista.
La clase CPersona
El listado siguiente muestra un ejemplo de una clase CPersona que define los atributos
privados nombre, direccin y telfono relativos a una persona, y los mtodos pbllicos
que forma la interfaz de esta clase de objetos. Esto es:
/**********************************************************
********************DEFINICIN CLASE PERSONA***************
**********************************************************/
//Constructores
public CPerona()
{
nombre=null;
direccion=null;
telefono=null;
}
//Metodos
La clase CListaTfnos
El listado siguiente muestra un ejemplo de lo que puede ser la clase lista de telfonos,
que denominaremos CListaTfnos. Define los atributos privados fes, flujo vinculado con
el fichero, nregs, nmero de registros, tamaoReg, tamao del registro en bytes, y
regsEliminados, indica si se elimin algn registro, as como los mtodos que se
describen a continuacin.
Constructor CListaTfnos
Cuando desde algn mtodo se cree un objeto CListaTfnos qu esperamos que ocurra?
Lgicamente que se cargue la lista de telfonos especificada, o bien que se cree una
nueva cuando el fichero especificado no exista. Por ejemplo:
/**********************************************************
********************DEFINICIN CLASE CLISTATFNOS***********
**********************************************************/
import java.io.*;
El resto de los mtodos en los que se puede producir un error de E/S, tambin lanzarn
una excepcin del tipo IOException para que sea atrapada por algubno de los mtodos
de la pila de llamadas. Esta es la tcnica que se sigue cuando no se desea manipular una
excepcin en el mtodo invocado, sino en el que invoca directa o indirectamente.
El mtodo aadirReg tiene como misin aadir un nuevo registro al final del fichero.
Para ello invoca al mtodo escribirReg pasando como argumento la posicin que
ocupar el nuevo registro, que coincide con el valor de nregs, y el objeto cuyos atributos
se desean escribir.
Leer un registro.
Para leer un registro del fichero que almacena la lista de telfonos, la clase ClistaTfnos
proporciona el mtodo leerReg. Este mtodo tiene un parmetro para identificar el
nmero de registro que se desea leer y devuelve el objeto CPersona creado a partir de
los datos nombre, direccin y telfono ledos desde el fichero.
Lo primero que hace el mtodo leerReg es verificar si el nmero de registro es vlido (el
primer registro es el 0). Si el nmero de registro est dentro de los lmites permitidos,
sita el puntero de L/E en la posicin de inicio correspondiente a ese registro dentro del
fichero y lee los datos nombre, direccin y telfono (esto se hace enviando al flujo fes
vinculando con el fichero, el mensaje read UTF, una vez por cada dato). Finalmente,
devuelve un objeto CPersona construido a partir de los datos ledos (el valor devuelto
ser null si el nmero de registro est fuera de lmites).
Puesto que el fichero manipulado con una lista de telfonos, parece lgico buscar el
registro que se desee eliminar por el nmero de telfono, ya que ste es nico. Para este
propsito escribiremos un mtodo eliminarReg con un parmetro que almacene el
nmero de telfono a eliminar y que devuelva un valor true si la operacin se realiza
con xito, o false en caso contrario.
El proceso seguido por le mtodo eliminar es leer registros del fichero, empezando por
el registro cero, y comprobar por cada uno de ellos si el telfono coincide con el valor
pasado como argumento (este proceso recibe el nombre de bsqueda secuencial). Si
existe un registro con el nmero de telfono buscado, no se borra fsicamente del
fichero, sino que se marca el registro poniendo un cero como nmero de telfono
(borrado lgico). Esta forma de proceder deja libertad al usuario de la clase CListaTfnos
para eliminar de una sola vez todos los registros marcados al finalizar su aplicacin (lo
que redunda en velocidad de ejecucin), para restaurar un registro marcado para
eliminar, para crear un histrico, etc.
Para saber si se marcaron registro para eliminar despus de haber trabajado con el
fichero, aadimos a la clase CListaTfnos el mtodo tieneRegsEliminados. Este mtodo
devuelve el valor del atributo privado regsEliminados, que inicialmente vale false y que
es cambiado a ture por el mtodo eliminarReg cuando se marca un registro para borrar.
Una operacin muy comn es localizar un determinado registro. Para ello lo ms normal
es buscar por el nombre del propietario de ese telfono, aunque tambin podra
realizarse la bsqueda por la direccin. El mtodo buscarReg que se expone a
continuacin permite realizar la bsqueda por cualquier subcadena perteneciente al
nombre. Para ello utiliza dos parmetros: la subcadena a buscar y a partir de qu registro
del fichero se desea buscar. Si la bsqueda termina con xito, el mtodo devuelve el
nmero del registro correspondiente; en otro caso devuelve el valor -1.
CPersona obj;
String nom;
Se observa que el mtodo buscarReg, al igual que el mtodo eliminarReg, realiza una
bsqueda secuencial desde el registro pos, comprobando si el nombre de alguno de ellos
contiene la subcadena str. Lgicamente, al realizar una bsqueda secuencial, el
resultado ser el nmero del primer registro que contenga en su nombre la subcadena
pasada como argumento; pero tambin es evidente que es posible continuar la bsqueda
a partir del siguiente registro, invocando de nuevo al mtodo buscarReg, pasando como
argumentos la misma subcadena y el nmero de registro siguiente al devuelto en el
proceso de bsqueda anterior.