Continuamos con la entrada y salida de ficheros en el curso de Java de RedesZone.net. Para los que no os acordéis, en la entrega anterior, hablamos sobre todo lo referido a la clase Scanner de Java, que nos facilitaba la lectura de ficheros de texto que siguen un determinado patrón.
En la entrega de hoy, que será la última entrega relacionada con entrada y salida, hablaremos sobre cómo utilizar los ficheros como tablas, es decir, si tenemos la necesidad, cómo es posible acceder a cualquier posición del fichero como si de una tabla se tratase.
Hasta ahora todos los ficheros se han manejado mediante clases que representan secuencias
En muchas ocasiones es conveniente poder acceder a los datos en cualquier orden, como en una tabla
• Las diferencias con un array son:
- Tamaño no limitado a priori
- Memoria persistente (no volátil)
Para ello Java dispone de la clase RandomAccessFile
• Permite acceso aleatorio al fichero
• No es un Stream
• Se puede usar para leer, o leer y escribir a la vez
En java son ficheros que contienen bytes
Se numeran con un índice que empieza en cero.
Existe un índice almacenado en el sistema que se llama el puntero de lectura/escritura
• Las lecturas y escrituras se hacen a partir de él, en secuencia
• Es posible cambiar el puntero de lectura/escritura
Operaciones más habituales
Ejemplo con tabla de datos
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | import java.io.*;/*** Clase que contiene los datos de un libro*/public class Libro {// constantes estáticaspublic static final int maxCaracteresTítulo=100;public static final int tamañoEnBytes =maxCaracteresTitulo+1 // título + \n+Integer.SIZE/8 // publicado+Double.SIZE/8 // precio+1; // tamaño par// atributos privadosprivate String título;private int publicado; // año de publicaciónprivate double precio; // en euros/*** Constructor al que se le pasan los datos del* libro*/public Libro(String titulo, int publicado,double precio) {// asegurarse de que el titulo no supera// maxCaracteresTítuloif (titulo.length()>maxCaracteresTítulo) {this.titulo=titulo.substring(0,maxCaracteresTítulo);} else {this.titulo=titulo;}this.publicado=publicado;this.precio=precio;}/*** Lee de fichero*/public static Libro leeDeFichero(RandomAccessFile fich) throws IOException {// lee los tres datos, por ordenint publi=fich.readInt();double prec=fich.readDouble();String tit=fich.readLine().trim();// crea y retorna el libroreturn new Libro(tit,publi,prec);} /** * Escribe en el fichero */public void escribeEnFichero( RandomAccessFile fich) throws IOException { // escribe los tres datos, por orden fich.writeInt(publicado); fich.writeDouble(precio); fich.writeBytes(titulo+'\n'); } métodos observadores, toString, ...} // clase Libro |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import java.io.*;/** * Tabla de libros persistente almacenada en * un fichero de acceso aleatorio */public class TablaLibros { // atributos privadosprivate RandomAccessFile fich; /** * Constructor al que se le pasa el nombre * del fichero */ public TablaLibros(String nombreFichero) throws FileNotFoundException { fich = new RandomAccessFile(nombreFichero,"rw"); }/** * Obtener el elemento de la tabla que esta en * "índice" */ public Libro obten(int índice) throws IOException { // posiciona el contador de lectura/escrituralong pos=indice*Libro.tamañoEnBytes; fich.seek(pos); // lee y retorna el libroreturn Libro.leeDeFichero(fich); }/** Escribir un libro en la posición "índice" * de la tabla */public void almacena(int índice, Libro l) throws IOException { // posiciona el contador de lectura/escrituralong pos=indice*Libro.tamañoEnBytes; fich.seek(pos); // escribe el libro l.escribeEnFichero(fich); } /** Cerrar la tabla */public void cerrar() throws IOException { fich.close(); }} // clase TablaLibros |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // ejemplo de uso de TablaLibrosTablaLibros t = null;try { t = new TablaLibros("random.dat"); Libro libro1 = new Libro("Java", 2006, 15.0); Libro libro2 = new Libro("1984", 1949, 25.0); t.almacena(0,libro1); t.almacena(1,libro2); Libro l1= t.obten(0);Libro l2= t.obten(1);} finally { if (t != null) { t.cerrar(); }} |
Para escribir objetos en ficheros de acceso aleatorio es preciso convertirlos a un array de bytes
• A este proceso se le llama “serialización”
Para leer el objeto hay que “deserializarlo”
La clase ByteArrayOutputStream nos ayuda en este proceso
Tener cuidado pues la serialización incluye objetos a los que se hace referencia
• Esto puede hacer que el tamaño del objeto serializado varíe mucho
• Para acceso aleatorio es conveniente tener tamaños fijos
Ejemplo de serialización
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // serializa un libro y le escribe en un ficheroRandomAccessFile fich = null;try { // abre el fichero de acceso aleatorio fich = new RandomAccessFile (nomFich, "rw"); // pone el puntero al principio fich.seek(0L);// serializa el libro convirtiéndolo a una // secuencia de bytesByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bos); out.writeObject(libro); out.close();// obtiene los bytes del libro serializado byte[] buf = bos.toByteArray();// escribe los bytes en el fichero fich.write(buf);} finally { if (fich!=null) { fich.close(); }} |
*Ejemplo de deserialización
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // recupera del fichero un libro serializadoRandomAccessFile fich = null;try { // abre el fichero de acceso aleatorio fich = new RandomAccessFile (nomFich, "r"); // pone el puntero al principio fich.seek(0L);// Lee un array de bytes del fichero byte[] bytes = new byte[(int) fich.length()]; fich.readFully(bytes);// Deserializa el array de bytes ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream(bytes)); libro=(Libro) in.readObject(); in.close();} finally { if (fich!=null) { fich.close(); }} |
| Fuente | ||
|




0 comentarios:
Publicar un comentario