Está en la página 1de 17

UNIVERSIDAD NACIONAL DE INGENIERÍA

FACULTAD DE CIENCIAS Y SISTEMAS


DEPARTAMENTO DE INFORMÁTICA

Guía de Laboratorio # 4.3


Nombre de la guía: Archivos aleatorios
Tiempo estimado: 2 horas
Autores:
 Yasser R. Membreño Gudiel
 Walger Herrera Treminio

Versión: 1.0

I. OBJETIVOS:
Que el estudiante sea capaz de:
 Implementar las clases definidas en el lenguaje de programación para la
construcción de aplicaciones que permiten escribir y leer datos de tipo primitivo
en un archivo de acceso aleatorio.

II. INTRODUCCIÓN TEÓRICA


Hasta el momento, se han trabajado con archivos secuenciales, lo que significa
que para leer el registro 99 hay que leer 98 registros previamente. Esto es
importante porque con los archivos aleatorios o de acceso directo no es
necesario leer esos 98 registros.

Los archivos aleatorios permiten el acceso a registros de forma directa, a través


de un apuntador que busca una ubicación particular.

Para que la búsqueda sea efectiva, los registros guardados deben tener el mismo
tamaño, de esta manera el cálculo de la posición de cada registro se calcularía
de la siguiente manera:

long pos = SIZE * n;

Donde la variable SIZE representa el tamaño de cada registro y n la cabecera


del archivo donde se almacena la cantidad de registros guardados. Suponiendo
que n = 1 y SIZE = 117, el valor de long = 117, que sería la posición donde se
guardaría el siguiente registro.
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
El paquete java.io contiene la clase RandomAccessFile, que proporciona las
capacidades que permiten este tipo de acceso directo. Así mismo, un objeto de
esta clase permite realizar operaciones de lectura y escritura.

RandomAccessFile

Un objeto de esta clase permite leer y escribir directamente a cualquier posición


dentro del archivo vinculado con él.

La especificación de la clase a continuación:

RandomAccessFile

Constructores

RandomAccessFile(String filename, String mode)

Crea un flujo de acceso directo al archivo especificado por filename para leer
y opcionalmente escribir. La variable mode hace referencia al modo del
archivo si se le pasa “r” el archivos será de solo lectura, si se le pasa “rw” el
archivo será de lectura y escritura.

RandomAccessFile(File file, String mode)

Crea un flujo de acceso directo al archivo especificado por el objeto file para
leer y escribir. La variable mode hace referencia al modo del archivo si se le
pasa “r” el archivos será de solo lectura, si se le pasa “rw” el archivo será de
lectura y escritura.

Métodos

long getFilePointer()

Devuelve la posición actual del apuntador en el archivo

long length()

Devuelve el tamaño del archivo

int read(byte[ ] b)
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
Lee un número de bytes de datos desde el flujo de entrada y los almacena en
el arreglo de bytes “b”. Devuelve los bytes leídos.

int read(byte[ ] b, int off, int size)

Lee desde una posición “off” hasta “size” bytes de datos desde el flujo de
entrada y los almacena en el arreglo de bytes “b”. Devuelve los bytes leídos.

boolean readBoolean()

Lee un byte y devuelve verdadero si el byte no es cero, falso si el byte es cero.

byte readByte()

Lee y devuelve un byte.

char readChar()

Lee dos bytes y devuelve un valor char.

double readDouble()

Lee 8 bytes y devuelve un valor de tipo double.

float readFloat()

Lee 4 bytes y devuelve un valor de tipo float.

int readInt()

Lee 4 bytes y devuelve un valor de tipo int.

long readLong()

Lee 8 bytes y devuelve un valor de tipo long.

short readShort()

Lee 2 bytes y devuelve un valor de tipo short.

String readUTF()

Lee una cadena que ha sido codificada usando el formato UTF-8 modificado.

seek(long pos)

Establece del desplazamiento del puntero del archivo, medido desde el


comienzo del archivo.
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
write(byte[ ] b, int off, int size)

Escribe “size” numero de bytes especificado por el arreglo de bytes


comenzando desde “off” hacia el flujo de salida de archivo

write(int b)

Escribe el byte especificado (los ocho bits bajos del argumento b) hacia el flujo
de salida de archivo

writeBoolean(boolean v)

Escribe un booleano hacia el flujo de datos de salida como un valor de 1-byte

writeByte(int v)

Escribe un byte hacia el flujo de datos de salida como un valor de 1-byte

writeBytes(String s)

Escribe la cadena “s” byte hacia el flujo de datos de salida como una secuencia
de bytes.

writeChar(char v)

Escribe el carácter “v” hacia el flujo de datos de salida como un valor de


2-byte, comenzando por el byte alto.

writeChars(String s)

Escribe la cadena “s” hacia el flujo de datos de salida como una secuencia de
caracteres.

writeDouble(double v)

Convierte el argumento double “v” al tipo de dato long usando el método


doubleToLongBits de la clase Double, luego escribe el valor long hacia el
flujo de datos de salida como una cantidad de 8-byte, comenzando por el byte
alto.

writeFloat(float v)

Convierte el argumento float “v” al tipo de dato int usando el método


floatToIntBits de la clase Float, luego escribe el valor int hacia el flujo de
datos de salida como una cantidad de 4-byte, comenzando por el byte alto.
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
writeInt(int v)

Escribe el valor entero “v” ” hacia el flujo de datos de salida como 4 bytes,
comenzando por el byte alto.

writeLong(long v)

Escribe el valor long “v” ” hacia el flujo de datos de salida como 8 bytes,
comenzando por el byte alto.

writeShort(int v)

Escribe el valor short “v” ” hacia el flujo de datos de salida como 2 bytes,
comenzando por el byte alto.

writeUTF(String str)

Escribe la cadena “str” hacia el flujo de datos de salida usando la


representación de cadenas Unicode UTF-8 modificado.

Creando un objeto RandomAccessFile


Para crear un objeto de la clase RandomAccessFile, se necesita importar el
paquete java.io.RandomAccessFile. Luego creamos el objeto así:

private void openRAF() throws IOException {


path = "estudiante.dat";
file = new File(path);

if (!file.exists()) {
file.createNewFile ();
raf = new RandomAccessFile(file, "rw");
raf.seek (0);
raf.writeInt (0);
raf.writeInt (0);
} else {
raf = new RandomAccessFile(file, "rw");
}
}
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
En el método openRAF (), observe que se declara en la definición del método el
relanzamiento de la excepcion IOException en caso que haya un error de ese
tipo.

Primero se verifica la existencia del archivo “estudiante.dat”, si el archivo no


existe se crea con la instrucción file.createNewFile (), a continuación se
instancia el objeto raf con el archivo y los modos de lectura y escritura (“rw”).
Seguido movemos el apuntador a la posición inicial del archivo con el método
raf.seek (0) y se escriben dos valores enteros (n y k) que serán las cabeceras
del archivo, los cuales representan la cantidad de elementos y el id consecutivo
de los registros de estudiantes, respectivamente.

En caso que el archivo ya existe solo se instancia la variable raf que representa
un objeto de la clase RandomAccessFile.

Ya podemos usar el objeto raf para llamar los métodos de lectura, escritura,
obtener la posición del puntero y mover el mismo hacia una nueva posición.

Ejemplo:
En el siguiente ejemplo se pretende guardar la información de un estudiante,
tales como nombres, apellidos, número de carnet y edad. Cada uno será un
registro guardado en un archivo aleatorio. Para ello se creara un objeto de la
clase RandomAccessFile. Además se utilizara el patrón de diseño llamado
DAO.

La estructura del archivo aleatorio será el siguiente:

n k 117 bytes 117 bytes 117 bytes …

Primer registro Segundo registro Tercer registro


Estudiante Estudiante Estudiante

Hay que recordar que para que el archivo aleatorio sea efectivo los registros
deben tener el mismo tamaño. Para calcular el estimado de bytes de cada
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
registro se toman cada variable del objeto a guardar, en este caso se obtendrían
las del objeto Estudiante, los campos serian:

Variable Tipo de dato bytes

id int 4 bytes

~20 caracteres

20*2 bytes + 3bytes por


nombres String
el UTF.

subtotal = 43 bytes

~20 caracteres

20*2 bytes + 3bytes por


apellidos String
el UTF.

subtotal = 43 bytes

~10 caracteres

10*2 bytes + 3bytes por


carnet String
el UTF.

subtotal = 23 bytes

edad int 4 bytes

Total 117 bytes

El tamaño de cada registro Estudiante almacenado en el archivo medirá 117


bytes.

Siguiendo con la arquitectura del ejemplo del laboratorio DataIOStream, se


crearan las clases Estudiante, EstudianteModelImpl y el App (tendrá el método
main). Las interfaces Model y EstudianteModel.

Primero se crea la clase POJO (Plain Old Java Object, Objeto Java Simple)

public class Estudiante {


private int id;
private String nombres;
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
private String apellidos;
private String carnet;
private int edad;

public Estudiante() {
}

public Estudiante(int id, String nombres, String apellidos, String carnet, int edad) {
this.id = id;
this.nombres = nombres;
this.apellidos = apellidos;
this.carnet = carnet;
this.edad = edad;
}

public int getId() {


return id;
}

public void setId(int id) {


this.id = id;
}

public String getNombres() {


return nombres;
}

public void setNombres(String nombres) {


this.nombres = nombres;
}

public String getApellidos() {


return apellidos;
}

public void setApellidos(String apellidos) {


this.apellidos = apellidos;
}

public String getCarnet() {


return carnet;
}

public void setCarnet(String carnet) {


this.carnet = carnet;
}

public int getEdad() {


UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
return edad;
}

public void setEdad(int edad) {


this.edad = edad;
}

Se crea la interfaz Model, se declaran los métodos básicos para la gestión de los
registros de Estudiante en el archivo, como son: Salvar un nuevo registro,
actualizar, eliminar y regresar todos los estudiantes guardados.

import java.io.IOException;

public interface Model<T> {


void save(T t)throws IOException;
void update(T t)throws IOException;
void delete(T t)throws IOException;
T[] findAll()throws IOException;
}

A continuación se crea la interfaz EstudianteModel, aquí se declaran los métodos


especializados, tales como, buscar estudiante por apellido, nombre, id y carnet.

import java.io.IOException;

public interface EstudianteModel extends Model<Estudiante>{


Estudiante findById(int id)throws IOException;
Estudiante findByCarnet(String carnet)throws IOException;
Estudiante[] findByLastname(String lastname)throws IOException;
Estudiante[] findByAgeRange(int min, int max)throws IOException;
}

A continuacion se implementan todos los métodos declarados en las interfaces.


Para ello se crea la clase EstudianteModelImpl la cual implementara la interfaz
EstudianteModel.

import java.io.File;
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import pojo.Estudiante;

public class EstudianteModelImpl implements EstudianteModel {

private File file;


private RandomAccessFile raf;
private String path;
private final int SIZE = 117;

public EstudianteModelImpl() {
path = "base.dat";
file = new File(path);
}

private void openRAF() throws IOException {


if (!file.exists()) {
file.createNewFile();
raf = new RandomAccessFile(file, "rw");
raf.seek(0);
raf.writeInt(0);
raf.writeInt(0);
} else {
raf = new RandomAccessFile(file, "rw");
}
}

private void closeRAF() throws IOException {


if (raf != null) {
raf.close();
}
}

public EstudianteModelImpl(String path) {


this.path = path;
file = new File(path);
}

public EstudianteModelImpl(File file) {


this.file = file;
}

@Override
public Estudiante findByCarnet(String carnet) throws IOException {
return null;
}
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA

@Override
public Estudiante[] findByLastname(String lastname) throws IOException {
Estudiante[] arr=findAll();
Estudiante[] founds=null;
int l, r, key;
Arrays.sort(arr,
(Estudiante t, Estudiante t1)->t.getLastnames().compareToIgnoreCase(t1.getLastnames()));
key=Arrays.binarySearch(arr, new Estudiante(0,null, null, lastname, 0),
(Estudiante t, Estudiante t1)->t.getLastnames().compareToIgnoreCase(t1.getLastnames()));
if(key>=0){
l=r=key;
while(--l>=0){
if(arr[l].getLastnames().equalsIgnoreCase(lastname)){
founds=addElement(founds, arr[l]);
}else{
break;
}
}
founds=addElement(founds, arr[key]);//elemento del medio, en el medio
while(++r<arr.length) {
if (arr[r].getLastnames().equalsIgnoreCase(lastname)) {
founds = addElement(founds, arr[r]);
} else {
break;
}
}
}
return founds;//si no se encuentra nada, se retornaria NULL, por valor inicializado
}

@Override
public Estudiante[] findByAgeRange(int min, int max) throws IOException {
return null;
}

@Override
public int save(Estudiante t) throws IOException {
openRAF();
raf.seek(0);
int n = raf.readInt();
int k = raf.readInt();

long pos = 8 + SIZE * n;


raf.seek(pos);
raf.writeInt(++k);
raf.writeUTF(fixString(t.getCarnet(),10));
raf.writeUTF(fixString(t.getNames(), 20));
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
raf.writeUTF(fixString(t.getLastnames(), 20));
raf.writeInt(t.getAge());

raf.seek(0);
raf.writeInt(++n);
raf.writeInt(k);

closeRAF();
return 1;
}

private String fixString(String text, int capacity) {


StringBuilder sb = null;

if (text == null) {
sb = new StringBuilder(capacity);
} else {
sb = new StringBuilder(text);
sb.setLength(capacity);
}

return sb.toString();
}

@Override
public Estudiante findById(int id) throws IOException {
Estudiante e = null;
openRAF();
raf.seek(0);
int n = raf.readInt();

if (id <= 0 || id > n) {


return null;
}

long pos = 8 + (id - 1) * SIZE;


raf.seek(pos);
int code = raf.readInt();
if (code == id) {
e = new Estudiante();
e.setId(code);
e.setCarnet(raf.readUTF());
e.setNames(raf.readUTF());
e.setLastnames(raf.readUTF());
e.setAge(raf.readInt());
closeRAF();
}
closeRAF();
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
return e;
}

@Override
public boolean update(Estudiante t) throws IOException {
int id=t.getId();
openRAF();
raf.seek(0);
int n=raf.readInt();
if(id<=0||id>n){
closeRAF();
return false;
}
long pos=8+(id-1)*SIZE;
raf.seek(pos);
int code=raf.readInt();//el id no se cambia
if(code==id){
raf.writeUTF(fixString(t.getCarnet(), 10));
raf.writeUTF(fixString(t.getNames(), 20));
raf.writeUTF(fixString(t.getLastnames(), 20));
raf.writeInt(t.getAge());
closeRAF();
return true;
}
closeRAF();
return false;
}

@Override
public boolean delete(Estudiante t) throws IOException {

}
@Override
public Estudiante[] findAll() throws IOException {
Estudiante estudiantes[] = null;
openRAF();
raf.seek(0);
int n = raf.readInt();
Estudiante e;
for (int i = 0; i < n; i++) {
long pos = 8 + i * SIZE;
raf.seek(pos);
e = new Estudiante();
e.setId(raf.readInt());
e.setCarnet(raf.readUTF());
e.setNames(raf.readUTF());
e.setLastnames(raf.readUTF());
e.setAge(raf.readInt());
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
estudiantes = addElement(estudiantes, e);
}
closeRAF();
return estudiantes;
}

private Estudiante[] addElement(Estudiante est[], Estudiante e) {


if (est == null) {
est = new Estudiante[1];
est[0] = e;
return est;
}

est = Arrays.copyOf(est, est.length + 1);


est[est.length - 1] = e;
return est;
}
}

En el método save se verifica si el objeto que se le está pasando es diferente de


null o el objeto “dos” es diferente de null. Luego se manda llamar los métodos
correspondientes para los tipos de datos del objeto estudiante, writeInt(int) para
enteros, writeUTF(String) para cadenas.

Finalmente se escribe la clase que contiene el método main, el cual nos permitirá
ejecutar la aplicación.

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import model.EstudianteModelImpl;
import pojo.Estudiante;

/**
*
* @author Sistema
*/
public class RandomApp {

public static void main(String[] args) {


Estudiante estudiante = null;
EstudianteModelImpl eimpl = null;
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
int opc = 0, i = 1;
Scanner scan = new Scanner(System.in);
do {
try {
menu();
System.out.print("opc: ");
opc = scan.nextInt();
eimpl = new EstudianteModelImpl();
switch (opc) {
case 1: {
estudiante = new Estudiante(i++, "2015-55251" + i, "Scottie" + i, "Pippen", 20);
eimpl.save(estudiante);
}
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8: {
System.out.format("%10s %20s %20s %15s %10s\n", "Id", "Nombres", "Apellidos",
"Carnet", "Edad");
for (Estudiante e : eimpl.findAll()) {
print(e);
}
}
break;
case 9: {
System.exit(0);
}
break;
default:
System.out.println("Opcion no valida!");
}
} catch (FileNotFoundException ex) {
Logger.getLogger(RandomApp.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(RandomApp.class.getName()).log(Level.SEVERE, null, ex);
}

} while (opc != 9);


UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
}

public static void menu() {


System.out.println("Menu de Opciones para el manejo de Estudiantes");
System.out.println("1. Registrar Estudiante");
System.out.println("2. Editar Estudiante");
System.out.println("3. Eliminar Estudiante");
System.out.println("4. Buscar Estudiante por Id");
System.out.println("5. Buscar Estudiante por Nombres");
System.out.println("6. Buscar Estudiante por Apellidos");
System.out.println("7. Buscar Estudiante por carnet");
System.out.println("8. Listar todos Estudiantes");
System.out.println("9. Salir");
}

public static void print(Estudiante e) {


System.out.format("%10s %20s %20s %15s %10s\n", String.valueOf(e.getId()),
e.getNames(), e.getLastnames(), e.getCarnet(), String.valueOf(e.getAge()));
}
}

Al seleccionar la opción 1 se agregara un registro de estudiante al archivo, con


los valores por defecto configurados (Se puede modificar para mandar a solicitar
al usuario los datos). Al seleccionar la opción 8 se mostraran todos los
Estudiantes agregados en el archivo. Quedan pendientes las otras opciones que
deberá de implementarlas como tarea.

Ejecución

Menú de Opciones para el manejo de Estudiantes


1. Registrar Estudiante
2. Editar Estudiante
3. Eliminar Estudiante
4. Buscar Estudiante por Id
5. Buscar Estudiante por Nombres
6. Buscar Estudiante por Apellidos
7. Buscar Estudiante por carnet
8. Listar todos Estudiantes
9. Salir
opc: 1
Menú de Opciones para el manejo de Estudiantes
1. Registrar Estudiante
2. Editar Estudiante
3. Eliminar Estudiante
4. Buscar Estudiante por Id
5. Buscar Estudiante por Nombres
UNIVERSIDAD NACIONAL DE INGENIERÍA
FACULTAD DE CIENCIAS Y SISTEMAS
DEPARTAMENTO DE INFORMÁTICA
6. Buscar Estudiante por Apellidos
7. Buscar Estudiante por carnet
8. Listar todos Estudiantes
9. Salir
opc: 8
Id Nombres Apellidos Carnet Edad
1 Pepito Pérez 2005-36251 25
2 Ana Alpina1 2015-55251 20
1 Ana2 Alpina2 2015-55251 20

III. ACTIVIDAD PRÁCTICA


Para la realización de los programas puede utilizarse cualquier editor de texto
(notepad, sublime Text 3, Visual Code).

Links de descarga:

Sublime Text 3: https://www.sublimetext.com/3

Visual Code: https://code.visualstudio.com/Download

Ejercicio 1:
Implementar los métodos que no se implementaron en el ejemplo, los cuales son:
editar estudiante, eliminar estudiante, buscar por nombre, apellidos, carnet y
rango de edad.

Ejercicio 2:

Implementar en la Clase App los case del switch que no se implementaron,


correspondientes a los métodos que implemento en el ejercicio 1.

IV Bibliografía
 Aguilar, l. J. (2011). Programacion en Java 6, Algoritmos y programacion
orientada a objetos. Mexico: McGraw Hill.
 baeldung. (16 de 01 de 2018). Binary Search Algorithm in Java. Obtenido de
http://www.baeldung.com/java-binary-search
 Oracle. (2017). The Java Tutorials. Obtenido de
https://docs.oracle.com/javase/tutorial/essential/io/rafs.html
 Tutorialspoint. (22 de Enero de 2018). https://www.tutorialspoint.com/.
Obtenido de
https://www.tutorialspoint.com/design_pattern/data_access_object_pattern.htm
 Tutorialspoint. (2018). Java.io package Tutorial. Obtenido de
https://www.tutorialspoint.com/java/io/java_io_randomaccessfile.htm

También podría gustarte