Problema 2 · Programació II UDL 2012
Tema: Ficheros en Java: texto secuencial y acceso directo binario · Del examen Examen Segundo Parcial (Curso 2012-2013) (2012)
Enunciado
Segundo parcial de Programación 2 (Curso 2012/2013)
A continuación se facilita información sobre el tamaño de los tipos primitivos en Java y una referencia de las clases y utilidades disponibles para la resolución del examen:
byte
char
int
long
float
double
8 bits
16 bits
32 bits
64 bits
32 bits
64 bits
Resumen de clases y métodos disponibles
Conversiones de tipo: (double) unEntero, (int) unLong.
class ConsoleProgram: void println(String msg), int readInt(String msg).
class Math: static final double PI = 3.141592...
class PackUtils: métodos estáticos de empaquetado y desempaquetado de tipos básicos y cadenas con límite:
packBoolean(boolean, byte[], int offset), unpackBoolean(byte[], int offset)
packChar(char, byte[], int offset), unpackChar(byte[], int offset)
packInt(int, byte[], int offset), unpackInt(byte[], int offset)
packLong(long, byte[], int offset), unpackLong(byte[], int offset)
packDouble(double, byte[], int offset), unpackDouble(byte[], int offset)
packLimitedString(String s, int maxLength, byte[] buffer, int offset)
unpackLimitedString(int maxLength, byte[] buffer, int offset)
class RandomAccessFile (todas sus operaciones lanzan IOException):
new RandomAccessFile(String fileName, String mode)
void close(), long length(), void seek(long pos), void setLength(long newLength)
int read(byte[] buff), int read(byte[] buff, int offset, int length)
void write(byte[] buff), void write(byte[] buff, int offset, int length)
class RandomGenerator: static RandomGenerator getInstance(), int nextInt(int n).
class String: static String valueOf(int i).
Problema 2 (6 puntos). Sorteos con RandomAccessFile
Se requiere desarrollar una aplicación para gestionar sorteos utilizando un fichero binario de acceso directo ( people.dat), en el cual no existen registros vacíos o huecos intermedios y que contiene los datos de todos los participantes.
El programa debe seleccionar al azar una serie de ganadores según la cantidad solicitada. Con el fin de evitar registros no válidos, cada persona premiada debe eliminarse del fichero sustituyendo su posición por la de la última persona almacenada en el archivo y truncando acto seguido la longitud del fichero.
La clase base para los registros es Person, cuya estructura original es:
public class Person {
private String name;
private String address;
private int age;
private boolean married;
public Person(String name, String address, int age, boolean married) {
this.name = name;
this.address = address;
this.age = age;
this.married = married;
}
public String toString() {
return this.name;
}
}
Requisitos y consideraciones:
Descomponga la solución en subproblemas y métodos auxiliares modulares antes de redactar el código definitivo.
Extienda la clase Person para incorporar las siguientes utilidades de serialización:
public static final int SIZE: constante pública con el número de bytes que ocupa un registro completo. En el fichero, las cadenas name y address tienen una longitud fija reservada de 20 y 50 caracteres, respectivamente.
public static Person fromBytes(byte[] record): método de factoría para reconstruir una persona a partir de su array de bytes.
public byte[] toBytes(): método para convertir la instancia actual a su representación en array de bytes.
El programa principal debe heredar de ConsoleProgram. Solicitará por teclado el número de premios a repartir y mostrará por pantalla el nombre de las personas seleccionadas.
Puede suponerse que el número de premios introducido es un entero estrictamente positivo y menor que el total de registros existentes en el fichero.
El número total de registros presentes en el fichero puede representarse sin pérdida mediante un dato de tipo int.
Acompañe el código con una breve explicación del diseño y razonamiento adoptado.
1.
2.
3.

Solución
Según los criterios oficiales de corrección
1. Implementación de la clase Person extendida con serialización
Solución: ```java public class Person { public static final int SIZE = (20 * 2) + (50 * 2) + 4 + 1; // 145 bytes private String name; private String address; private int age; private boolean married; public Person(String name, String address, int age, boolean married) { this.name = name; this.address = address; this.age = age; this.married = married; } public byte[] toBytes() { byte[] buffer = new byte[SIZE]; int offset = 0; PackUtils.packLimitedString(this.name, 20, buffer, offset); offset += 20 * 2; PackUtils.packLimitedString(this.address, 50, buffer, offset); offset += 50 * 2; PackUtils.packInt(this.age, buffer, offset); offset += 4; PackUtils.packBoolean(this.married, buffer, offset); return buffer; } public static Person fromBytes(byte[] record) { int offset = 0; String name = PackUtils.unpackLimitedString(20, record, offset); offset += 20 * 2; String address = PackUtils.unpackLimitedString(50, record, offset); offset += 50 * 2; int age = PackUtils.unpackInt(record, offset); offset += 4; boolean married = PackUtils.unpackBoolean(record, offset); return new Person(name, address, age, married); } public String toString() { return this.name; } } ```
2. Implementación del programa principal (clase que hereda de ConsoleProgram)
Solución: ```java import java.io.RandomAccessFile; import java.io.IOException; public class SorteoProgram extends ConsoleProgram { private Person readPersonAt(RandomAccessFile raf, int index) throws IOException { byte[] buffer = new byte[Person.SIZE]; raf.seek((long) index * Person.SIZE); raf.read(buffer); return Person.fromBytes(buffer); } private void writePersonAt(RandomAccessFile raf, Person p, int index) throws IOException { raf.seek((long) index * Person.SIZE); raf.write(p.toBytes()); } public void run() { RandomAccessFile raf = null; try { raf = new RandomAccessFile("people.dat", "rw"); int totalRecords = (int) (raf.length() / Person.SIZE); int numPrizes = readInt("Introduzca el numero de premios: "); RandomGenerator rnd = RandomGenerator.getInstance(); for (int i = 0; i < numPrizes; i++) { int winnerIndex = rnd.nextInt(totalRecords); Person winner = readPersonAt(raf, winnerIndex); println("Ganador " + (i + 1) + ": " + winner.toString()); int lastIndex = totalRecords - 1; if (winnerIndex != lastIndex) { Person lastPerson = readPersonAt(raf, lastIndex); writePersonAt(raf, lastPerson, winnerIndex); } totalRecords--; raf.setLength((long) totalRecords * Person.SIZE); } } catch (IOException e) { println("Error de acceso al fichero: " + e.getMessage()); } finally { if (raf != null) { try { raf.close(); } catch (IOException e) { println("Error al cerrar el fichero."); } } } } } ```
3. Breve explicación del diseño, cálculo del tamaño y razonamiento adoptado
Solución: Cálculo del tamaño del registro (145 bytes) y diseño modular separando lectura/escritura en métodos auxiliares (readPersonAt, writePersonAt). La eliminación eficiente sustituye el registro premiado por el último (si no era ya el último) y reduce la longitud del fichero con raf.setLength().
La explicación paso a paso, hecha con IA, es Premium. Premium
Resuélvelo aquí mismo: corrección automática, pistas y solución paso a paso.