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.
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.

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.
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 | 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.
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 | 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.
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 102 103 | // 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.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | /* 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.
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 | // 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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(); } } |