Saltar al contenido principal

Acceso secuencial frente a acceso aleatorio

Dos formas de leer un fichero​

Hasta ahora, todas las operaciones vistas (Files.readString, Files.readAllLines, un Stream de líneas) son de acceso secuencial: se lee el fichero en orden, de principio a fin, sin poder "saltar" a una posición arbitraria sin antes pasar por las anteriores.

El acceso aleatorio permite posicionarse directamente en cualquier byte del fichero sin leer lo anterior, y leer o escribir desde ahí.

Acceso secuencialAcceso aleatorio
Orden de lectura/escrituraDe principio a finCualquier posición, en cualquier orden
API típicaFiles.readString, BufferedReader, Stream<String>RandomAccessFile, SeekableByteChannel
Coste de acceder a un dato concretoProporcional a su posición en el ficheroConstante (si se conoce el desplazamiento)
Caso de uso naturalProcesar todo el contenido: logs, informes, exportacionesRegistros de tamaño fijo, índices, ficheros muy grandes donde solo interesa un fragmento

RandomAccessFile​

RandomAccessFile es la clase clásica (anterior a NIO.2) para acceso aleatorio. Permite moverse con seek(posicion) y leer o escribir desde ahí:

import java.io.RandomAccessFile;

try (RandomAccessFile raf = new RandomAccessFile("registros.dat", "rw")) {
long tamanoRegistro = 64; // bytes por registro, todos de igual longitud
int indice = 3;

raf.seek(indice * tamanoRegistro); // saltar directamente al registro 3
byte[] buffer = new byte[(int) tamanoRegistro];
raf.readFully(buffer);

String contenido = new String(buffer, java.nio.charset.StandardCharsets.UTF_8).trim();
System.out.println(contenido);
}

Esto solo funciona de forma práctica cuando los registros tienen tamaño fijo: si cada registro ocupa siempre 64 bytes, calcular la posición del registro n es una simple multiplicación. Con registros de longitud variable, hace falta un índice aparte que guarde el desplazamiento de cada uno.

RandomAccessFile también permite escribir en mitad de un fichero sin reescribirlo entero:

try (RandomAccessFile raf = new RandomAccessFile("registros.dat", "rw")) {
raf.seek(2 * 64); // posición del registro 2
raf.write("dato actualizado".getBytes(java.nio.charset.StandardCharsets.UTF_8));
}
aviso

Escribir en mitad de un fichero sobrescribe los bytes existentes en esa posición; no los desplaza. Si el nuevo contenido no ocupa exactamente el mismo número de bytes que el anterior, se corrompe la estructura del fichero. El acceso aleatorio exige que el formato del fichero esté diseñado para ello (registros de tamaño fijo, o un índice que localice cada registro).

SeekableByteChannel: la versión NIO.2​

java.nio.file.Files.newByteChannel devuelve un SeekableByteChannel, la forma moderna de hacer lo mismo integrada con Path:

import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

Path fichero = Path.of("registros.dat");

try (SeekableByteChannel canal = Files.newByteChannel(
fichero, StandardOpenOption.READ, StandardOpenOption.WRITE)) {

long tamanoRegistro = 64;
int indice = 3;

canal.position(indice * tamanoRegistro);

ByteBuffer buffer = ByteBuffer.allocate((int) tamanoRegistro);
canal.read(buffer);
buffer.flip();

byte[] datos = new byte[buffer.remaining()];
buffer.get(datos);
System.out.println(new String(datos, java.nio.charset.StandardCharsets.UTF_8).trim());
}

SeekableByteChannel se integra mejor con el resto de java.nio (buffers, canales asíncronos) y es la opción preferible en código nuevo; RandomAccessFile sigue siendo válida y se encuentra a menudo en código existente.

Cuándo elegir cada una​

  • Acceso secuencial cuando el objetivo es procesar el fichero completo, el orden natural de lectura coincide con el orden de procesamiento, o el fichero es de texto con líneas de longitud variable (logs, CSV sin índice, documentos).
  • Acceso aleatorio cuando solo interesa una parte concreta de un fichero grande, se necesita actualizar un registro puntual sin reescribir todo el fichero, o el formato ya está diseñado con registros de tamaño fijo o con un índice de posiciones.
información

El acceso aleatorio no es "más rápido" en general: es más rápido para llegar a un punto concreto. Si de todas formas hay que leer el fichero entero, el acceso secuencial suele ser más simple y no menos eficiente.