"¡Hola, amigo!"

"¡Hola, Bilaabo! ¿Cómo va la vida?"

"Genial. Ayer intenté deshacerme de algunos parásitos, pero hasta ahora no he tenido mucho éxito. Y luego tuve que pasar la noche en el bote de basura otra vez".

"Entonces... ¿todo sigue genial?"

"Podrías decirlo."

"Bien. Entonces, ¿qué tienes para mí hoy?"

"Hoy les contaré sobre la clase RandomAccessFile ".

Archivo de acceso aleatorio, etc. - 1

"La cuestión es que FileInputStream y FileOutputStream representan archivos como flujos: solo puede leerlos y escribirlos secuencialmente".

"Eso no siempre es muy conveniente. A veces es necesario escribir un par de líneas en medio de un archivo o leer un par de páginas de texto desde el final de un archivo de varios megabytes. No sería muy eficiente leer todo el archivo para estas tareas".

"La clase RandomAccessFile se creó para resolver este problema. Puede usarla para escribir en cualquier parte del archivo, leerlo, así como leer y escribir en el archivo al mismo tiempo".

"¡Que interesante!"

"Sí. En realidad es bastante conveniente".

"Pero, ¿cómo se lee desde una ubicación arbitraria?"

"Todo es bastante simple. Imagine que tiene abierto un editor de texto, como el Bloc de notas. Tiene un cursor. Cuando escribe algo, el texto se agrega donde esté el cursor. Leer un archivo es lo mismo. La lectura comienza desde donde sea que esté el 'cursor'. Al leer/escribir, el cursor se mueve automáticamente".

"Aquí, será mejor mostrarte un ejemplo:"

Lectura de un archivo:
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");

// Move the «cursor» to the 100th character.
raf.seek(100);

// Read the line starting from the current cursor position until the end of the line.
String text = raf.readLine();

// Close the file.
raf.close();

"En este ejemplo, me gustaría llamar su atención sobre dos cosas:"

"Primero, la creación del objeto RandomAccessFile . El segundo argumento es la letra r. Esto significa que el archivo se abre para lectura ( r - read ). Si desea abrir un archivo para lectura y escritura, debe pasar « rw » al constructor, en lugar de simplemente « r »."

"Segundo, mire el método de búsqueda. Puede usar este método para saltar alrededor del archivo y cambiar la posición del cursor para la operación de lectura/escritura actual. Cuando se abre un archivo por primera vez, el cursor se establece en el byte 0. O, más exactamente, antes del byte cero".

"¿Entendí correctamente? Abrimos el archivo y el cursor está al principio, en la posición 0. Luego llamamos a seek y movemos el cursor al byte número 100. Y cuando llamamos a readLine , comienza a leer desde el byte número cien . ¿Bien?"

"Sí. Pero quiero llamar su atención sobre el hecho de que el método de búsqueda le permite saltar arbitrariamente alrededor del archivo. Por ejemplo:"

Lectura de un archivo:
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");

// The "cursor" is at the 0th character.
String text1 = raf.readLine();

// Move the "cursor" to the 100th character.
raf.seek(100);
String text2 = raf.readLine();

// Move the "cursor" to the 0th character.
raf.seek(0);
String text3 = raf.readLine();

// Close the file
raf.close();

"En este ejemplo, primero leemos una línea que comienza en el byte 0. Luego saltamos al byte cien y leemos una línea allí. Luego saltamos al byte 0 nuevamente y leemos una línea. Eso significa que text1 y text3 son idénticos instrumentos de cuerda."

"Ah. Eso aclara las cosas."

"Genial. Entonces aquí hay otro ejemplo:"

Lectura de un archivo:
// rw - read/write, the file is opened for reading and writing.
RandomAccessFile raf = new RandomAccessFile("seek.txt", "rw");

// Write to the file, starting from the 0th byte.
raf.writeBytes("It is a string");

// Move the "cursor" to the 8th character.
raf.seek(8);

// Write "surprise!" to the file.
raf.writeBytes("surprise!");

// Close the file.
raf.close();

"Aquí abrimos el archivo para lectura y escritura pasando « rw » ( lectura/escritura ) al constructor".

Luego escribimos « Es una cadena » en el archivo.

"Luego movemos el cursor al octavo byte (que resulta ser el comienzo de la palabra 'cadena')"

"Entonces escribimos « ¡sorpresa !»"

"Como resultado, el archivo contiene « ¡ Es una sorpresa !»"

"Entonces, ¿los bytes no se insertan en el medio del archivo, sino que reemplazan a los que estaban allí?"

"Sí."

"¿Qué pasa si movemos el cursor hasta el final del archivo?"

"Luego, los bytes se escribirán hasta el final y el archivo se hará más grande. Así que sería casi como escribir texto en un editor de texto".

"Hmm. Creo que entiendo todo. ¿Podría proporcionar una lista completa de los métodos de la clase RandomAccessFile ?"

"Claro aquí tienes:"

Método Descripción
int read() Lee un byte y lo devuelve.
int read(byte b[], int off, int len) Lee una matriz de bytes
int read(byte b[]) Lee una matriz de bytes
void readFully(byte b[]) Lee una matriz de bytes y espera a que se agreguen nuevos bytes si no hay suficientes para llenar la matriz
int skipBytes(int n) Saltar n bytes. En otras palabras, esto mueve el cursor hacia adelante n bytes.
void write(int b) Escribe un byte en la ubicación del cursor.
void write(byte b[]) Escribe una matriz de bytes en la ubicación del cursor
void write(byte b[], int off, int len) Escribe una matriz de bytes en la ubicación del cursor
long getFilePointer() Devuelve el número del byte al que apunta el cursor. Puede variar de 0 a la longitud del archivo.
void seek(long pos) Mueve el «cursor» utilizado para leer/escribir a la ubicación especificada
long length() Devuelve la longitud del archivo.
void setLength(long newLength) Establece una nueva longitud de archivo. Si el archivo era más grande, se trunca; si era más pequeño, entonces expande el archivo y llena el nuevo espacio con ceros
void close() Cierra el archivo
boolean readBoolean() Lee un valor booleano desde la posición actual del cursor en el archivo
byte readByte() Lee un byte de la posición actual del cursor en el archivo
char readChar() Lee un carácter de la posición actual del cursor en el archivo
int readInt() Lee un int desde la posición actual del cursor en el archivo
long readLong() Lee un largo desde la posición actual del cursor en el archivo
float readFloat() Lee un flotante desde la posición actual del cursor en el archivo
double readDouble() Lee un doble desde la posición actual del cursor en el archivo
String readLine() Lee una línea del archivo y la devuelve.
void writeBoolean(boolean v) Escribe un valor booleano en el archivo (a partir de la posición del cursor)
void writeByte(int v) t Escribe un byte en el archivo (a partir de la posición del cursor)
void writeChar(int v) Escribe un carácter en el archivo (a partir de la posición del cursor)
void writeInt(int v) Escribe un int en el archivo (a partir de la posición del cursor)
void writeLong(long v) Escribe un largo en el archivo (a partir de la posición del cursor)
void writeFloat(float v) Escribe un flotante en el archivo (a partir de la posición del cursor)
void writeDouble(double v) Escribe un doble en el archivo (a partir de la posición del cursor)
void writeBytes(String s) Escribe una cadena en el archivo (a partir de la posición del cursor)
void writeChars(String s) Escribe una cadena en el archivo (a partir de la posición del cursor)

"Hmm. Entonces, no hay nada nuevo aquí. Excepto quizás los pares de métodos seek()/getFilePointer() y length()/setLength()".

"Sí, Amigo. Todo está más o menos igual. ¿Pero no es eso conveniente?"

"Es conveniente. Gracias, Bilaabo, por una lección interesante y por los ejemplos que me diste".

"¡Encantado de ayudar, Amigo, mi amigo!"