Saltar al contenido

RandomAccessFile en java. Archivos de acceso aleatorio.

Si traducimos el nombre de la clase RandomAccessFile al español, estaremos hablando de archivos de acceso aleatorio. Es decir, con esta clase, podemos acceder de forma aleatoria a un archivo o fichero. Además, los archivos de este tipo, se pueden leer, o bien leer y escribir a la vez.

Por otra parte, estos archivos no son stream y se numeran por un índice que empieza por cero. Este índice, se llama puntero o cursor de lectura/escritura e indica la posición a partir de la cual se empezará a leer o escribir en el archivo. Es importante indicar que la información almacenada en este tipo de archivos, se guarda en forma de bytes. Esto quiere decir que este la clase RandomAccessFile trata del archivo como un array o arreglo de bytes.

Índice de contenidos

    Como determinar la longitud de un dato usando la clase RandomAccessFile.

    Para poder determinar cuanto ocupa cada registro en un archivo de acceso aleatorio, debemos tener en cuenta los bytes de cada uno de los datos. De esta forma, dependiendo del tipo de dato que queramos almacenar, cada registro ocupará un tamaño u otro. A continuación, mostramos una imagen con el tamaño en bytes que ocupa tipo de dato.

    RandomAccessFile en java. Tamaño de los tipos de datos.
    Tamaño de los tipos de datos en java para archivos de acceso aleatorio

    Hay que tener en cuenta que los datos tipo String (tipo texto), en java son considerados como objetos. Por este motivo, un dato tipo String, se considera un array de caracteres tipo char. Esto quiere decir que la información de tipo String, ocupará dos bytes por cada carácter tipo char. A esta información, se le deben sumar los bytes ocupados por los espacios en blanco y los saltos de línea.

    Uso de objetos en ficheros de acceso aleatorio.

    Para poder almacenar objetos en archivos aleatorios con la clase RandomAccessFile, es necesario convertirlos a un array de bytes. A este proceso se le llama serialización. Esto se consigue indicándole a la clase de java, que debe implementar la interfaz serializable.

    Por otro lado, para poder leer un fichero que contiene objetos creados en java, debemos deserializar dicho objeto. Esto lo conseguimos con la clase ByteArrayOutputStream().

    A continuación, empezaremos con el desarrollo un ejemplo para explicar el uso de la clase RandomAccessFile. Para este ejemplo, como ocurre con el ejemplo anterior, haremos uso de las clases contenidas en el paquete “java.io” correspondientes a la API de java. También usaremos una clase llamada Persona con sus atributos y sus métodos.

    package archivosaleatorios;
    
    import java.io.Serializable;
    
    public class Persona implements Serializable {
        /* Declaramos los atributos o características de nuestro objeto persona:
        DNI, nombre, apellidos, edad y sexo*/
        private int id;
        private String dni;
        private String nombre;
        private String apellidos;
        private int edad;
        private char sexo;
        
        Persona(){
            
        }
        
        // Creamos los métos setter (para establecer valores al objeto
        // y getter que devolverá el valor de cada uno de los atributos del objeto
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getId() {
            return id;
        }
        
        public void setDni(String dni) {
            this.dni = dni;
        }
        
        public String getDni() {
            return dni;
        }
    
        public void setNombre(String nombre) {
                this.nombre = nombre;   
        }
    
        public String getNombre() {
            return nombre;
        }
    
        public void setApellidos(String apellidos) {
            this.apellidos = apellidos;
        }
       
        public String getApellidos() {
            return apellidos;
        }
    
        public void setEdad(int edad) {
            this.edad = edad;
        }
    
        public int getEdad() {
            return edad;
        }
    
        public void setSexo(char sexo) {
            this.sexo = sexo;
        }
     
        public char getSexo() {
            return sexo;
        }
        
        /* Sobreescribimos el método toString() de la clase Object. Esto lo hacemos
        para devolver todos los datos de la persona en cuestión.*/
    
        @Override
        public String toString() {
            return this.getDni() + ", " + this.getNombre() + ", " 
                    + this.getApellidos () + ", " + this.getEdad()+ ", " 
                    + this.getSexo() + ".\n";
        } 
    }
    

    Almacenar objetos en archivos de acceso aleatorio. Escritura con RandomAccessFile.

    Para este ejemplo crearemos las siguientes variables dentro de la clase que contiene el método main. Todas ellas las crearemos a nivel de clase para que puedan utilizarse en cualquier método de la clase principal.

    package archivosaleatorios;
    
    // Importamos las clases del paquete java.io
    // donde encontramos la clase RandomAccessFile
    import java.io.*;
    import java.util.*;
    
    public class ArchivosAleatorios {
    
        // Creamos una variable para leer los datos que se piden por teclado
        private static Scanner lectura = new Scanner(System.in);
        
        /* Variables para almacenar los datos de cada persona que se introduce
        por teclado. El sexo será 'M' para masculino y 'F' para femenino. Además
        los datos, tendrán una longitud fija máxima*/
        
        private static String idPersona=""; // Almacena un id unico de la persona
        private static int id=0; // 4 bytes
        private static String dniPersona=""; // 9 por 2 bytes = 18 bytes
        private static String nombrePersona=""; // 20 por 2 bytes = 40 bytes
        private static String apellidoPersona=""; // 20 por 2 bytes = 40 bytes
        private static String edadPersona=""; // Contendrá la edad en texto.
        private static int edadEntera=0; // 4 bytes
        private static char sexoPersona='M'; // 1 caracter x 2 bytes = 2 bytes
        // Almacena los bytes que ocupa un registro como máximo.
        private static int longitudRegistro =110;
        
        // Variable objeto de tipo Persona que almacena un nuevo objeto Persona.
        private static Persona nuevaPersona = new Persona();
        
        // Creamos una variable objeto de tipo RandomAccessFile.
        private static RandomAccessFile archivo=null;
        
        /* Variables necesarias para serializar los objetos de tipo Persona
        
        Varaibles para poder escribir en el fichero*/
        private static byte []array=null;
        private static ByteArrayOutputStream escribir=null;
        private static ObjectOutputStream salida=null;
        
        // Variables para poder leer el fichero
        private static ByteArrayInputStream leer=null;
        private static ObjectInputStream entrada = null;
    

    En segundo lugar, crearemos un método para pedir los datos por teclado al usuario.

    Método que pide los datos al usuario.

    // Metodo que pide los datos de la persona por teclado.
        private static boolean pedirDatos(){
            
            // Pedimos al usuario cada uno de los datos de la persona
            do{
                System.out.println("Introduce el ID de la persona. Este ID "
                        + "debe ser mayor que cero: ");
                idPersona=lectura.nextLine();
                
                // Intentamos pasarlo a número
                try {
                    id=Integer.parseInt(idPersona);
                } catch (NumberFormatException e) {
                    System.out.println("Debes introducir un ID mayor que cero");
                }
            }while(idPersona.isEmpty() || id<=0);
            
            do{
                System.out.println("Introduce el DNI de la persona: ");
                dniPersona=lectura.nextLine();
            }while(dniPersona.isEmpty() || dniPersona.length() !=9);
            
            do{
                System.out.println("Introduce el nombre de la persona: ");
                nombrePersona=lectura.nextLine();
            }while(nombrePersona.isEmpty() || nombrePersona.length()>20);
            
            do{
                System.out.println("Introduce un apellido de la persona: ");
                apellidoPersona=lectura.nextLine();
            }while(apellidoPersona.isEmpty() || apellidoPersona.length()>20);
            
            do{
                System.out.println("Introduce la edad de la persona: ");
                edadPersona=lectura.nextLine();
                try {
                    edadEntera=Integer.parseInt(edadPersona);
                } catch (NumberFormatException e) {
                    System.out.println("Debes introducir un número entero");
                }
            }while(edadPersona.isEmpty() || edadEntera<=0);
            
            do{
                System.out.println("Introduce el sexo de la persona. 'M' para "
                        + "masculino o 'F' para femenino. (Sin las comillas): ");
                sexoPersona=lectura.next().charAt(0);
            }while(sexoPersona !='M' && sexoPersona !='F');
            
            // Pasamos los datos al objeto Persona
            nuevaPersona.setId(id);
            nuevaPersona.setDni(dniPersona);
            nuevaPersona.setNombre(nombrePersona);
            nuevaPersona.setApellidos(apellidoPersona);
            nuevaPersona.setEdad(edadEntera);
            nuevaPersona.setSexo(sexoPersona);
            // Devolvemos true
            return true;
        }
    

    A continuación, crearemos el método para escribir datos en el archivo o fichero.

    Método para escribir en un archivo con la clase RandomAccessFile.

    /* Método para escribir en un archivo de acceso aleatorio con la clase
        RandomAccessFile.*/
        
        private static void escribirEnArchivoAleatorio(){
            try {
                /* Creamos o abrimos un nuevo archivo. En este caso:
                El primer parámetro hace referencia a la ruta del archivo.
                El segundo parametro es el siguiente:
                - r - read. Solo lectura.
                - rw - read/wirte. Lectura y escritura */
                archivo = new RandomAccessFile("src/Registrar_personas.txt", "rw");
                
                // Ponemos el puntero al final del archivo
                archivo.seek(archivo.length());
                
                // Serializamos el objeto Persona
                // Lo convertimos en una secuencia de bytees.
                escribir= new ByteArrayOutputStream();
                salida = new ObjectOutputStream(escribir);
                salida.writeObject(nuevaPersona.toString());
                
                // Cerramos el objeto.
                salida.close();
                
                // obtenemos los bytes del libro serializado
                array = escribir.toByteArray();
                
                // Escribimos los bytes en el archivo.
                archivo.write(array);
                
                // Cerramos el archivo
                archivo.close();
            } catch (Exception e) {
                System.out.println("No se puede escribir en el archivo" 
                + e.getMessage());
            }
        }
    

    Para poder leer un archivo de acceso aleatorio con la clase RandomAccessFile, crearemos un método para a parte de estos dos dentro de la misma clase.

    Función para leer archivos de acceso aleatorio.

    Este método se desarrolla entre las líneas 142 a la 181.

    // Metodo para leer el archivo de acceso aleatorio
        private static void leerArchivoAleatorio(){
            try {
                /* Creamos o abrimos un nuevo archivo. Este archivo lo crearemos
                dentro de la carpeta src de nuestro proyecto. Además debemos tener
                en cuenta que el constructor de la clase RandomAccessFile recibe
                2 parámetros:
                El primero hace referencia a la ruta del archivo.
                El segundo hace referencia al modo de apertura del archivo:
                - r - read. Solo lectura.
                - rw - read/wirte. Lectura y escritura */
                archivo = new RandomAccessFile("src/Registrar_personas.txt", "r");
                
                // Nos posicionamos al principio del fichero
                archivo.seek(0);
                
                // Almacenamos los bytes del fichero en un array de bytes
                array = new byte[(int)archivo.length()];
                
                // Leemos todos los bytes del fichero
                archivo.readFully(array);
                
                // Convertimos ese array de bytes en un objeto.
                leer = new ByteArrayInputStream(array);
                entrada = new ObjectInputStream(leer);
                
                /* Hacemos una conversion de lo que lee el ObjectInputStream
                a un objeto de tipo Persona y lo almacenamos
                en la variable objeto nuevaPersona*/
                nuevaPersona=(Persona) entrada.readObject();
                System.out.println(nuevaPersona);
                // Cerramos el objeto ObjectInputStream
                entrada.close();
                
                
            } catch (Exception e) {
                System.out.println("No se puede leer el archivo" 
                + e.getMessage());
            }
        }
    

    Finalmente para que el programa funcione, debemos llamar a ambos métodos desde el main.

    Metodo main del programa.

    El método main serán las lineas desde la 183 a la línea 203, la cual incluye la llave de cierre de la clase que estamos trabajando.

    public static void main(String[] args) {
            
            /*Si a la hora de pedir los datos devuelve true, es que los datos
            se han introducido de forma correcta.*/
            if(pedirDatos()){
                
                // Si los datos son correctos, intentamos...
                try {
                    escribirEnArchivoAleatorio();
                    // Escribimos en el archivo.
                    //escribirEnArchivoAleatorio(nuevaPersona);
                } catch (Exception e) {
                    System.out.println("No se ha podido registrar la persona.");
                }
            }
            
            /* Si se quiere leer el archivo,
            solo debemos llamarlo desde este método, de la siguiente manera*/
            leerArchivoAleatorio();
        }
    }
    

    DESCARGAR PROYECTO

    Configuración