Curso de Java. Entrada y salida de ficheros

Curso de Java. Entrada y salida de ficheros

Adrián Crespo

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:
  1. Tamaño no limitado a priori
  2. 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. Tienes varias opciones de cursos de Java por Internet.

    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

    Si escribimos pasado el final del fichero, su tamaño se amplía

    Operaciones más habituales

    Ejemplo con tabla de datos

    [java]
    import java.io.*;

    /**

    * Clase que contiene los datos de un libro

    */

    public class Libro {

    // constantes estáticas

    public 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 privados

    private String título;

    private int publicado; // año de publicación

    private 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ítulo

    if (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 orden

    int publi=fich.readInt();

    double prec=fich.readDouble();

    String tit=fich.readLine().trim();

    // crea y retorna el libro

    return 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

    [/java]

     

    [java]

    import java.io.*;

    /**
    * Tabla de libros persistente almacenada en
    * un fichero de acceso aleatorio
    */
    public class TablaLibros {
    // atributos privados
    private 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/escritura
    long pos=indice*Libro.tamañoEnBytes;
    fich.seek(pos);

    // lee y retorna el libro
    return 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/escritura
    long 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

    [/java]

     

    [java]

    // ejemplo de uso de TablaLibros
    TablaLibros 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();
    }
    }

    [/java]

    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

    [java]

    // serializa un libro y le escribe en un fichero
    RandomAccessFile 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 bytes
    ByteArrayOutputStream 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();
    }
    }

    [/java]

    Ejemplo de deserialización

    [java]
    // recupera del fichero un libro serializado
    RandomAccessFile 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();
    }
    }

    [/java]

1 Comentario