"Ciao, Amico!"

"Ciao, Bilaabo! Come va la vita?"

"Fantastico. Ieri ho provato a sbarazzarmi di alcuni parassiti, ma finora non ho avuto molto successo. E poi ho dovuto passare di nuovo la notte nel bidone della spazzatura."

"Allora... va ancora tutto bene?"

"Potresti dire che."

"Bene. Allora cosa hai per me oggi?"

"Oggi ti parlerò della classe RandomAccessFile ."

RandomAccessFile, ecc. - 1

"Il fatto è che FileInputStream e FileOutputStream rappresentano i file come flussi: puoi solo leggerli e scriverli in sequenza."

"Non è sempre super conveniente. A volte è necessario scrivere un paio di righe nel mezzo di un file o leggere un paio di pagine di testo dalla fine di un file multi-megabyte. Non sarebbe molto efficiente leggere l'intero file per queste attività."

"La classe RandomAccessFile è stata creata per risolvere questo problema. Puoi usarla per scrivere ovunque nel file, leggere da esso, così come leggere e scrivere nel file allo stesso tempo."

"Interessante!"

"Sì. In realtà è abbastanza comodo."

"Ma come si fa a leggere da una posizione arbitraria?"

"È tutto piuttosto semplice. Immagina di avere un editor di testo, come Blocco note, aperto. Ha un cursore. Quando digiti qualcosa, il testo viene aggiunto ovunque si trovi il cursore. La lettura di un file è la stessa. La lettura inizia da ovunque si trovi il "cursore". Durante la lettura/scrittura, il cursore si sposta automaticamente."

"Ecco, sarà meglio mostrarti un esempio:"

Leggere un file:
// 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();

"In questo esempio, vorrei attirare la tua attenzione su due cose:"

"In primo luogo, la creazione dell'oggetto RandomAccessFile . Il secondo argomento è la lettera r. Ciò significa che il file è aperto per la lettura ( r - read ). Se si desidera aprire un file per la lettura e la scrittura, è necessario passare « rw » al costruttore, invece che solo « r »."

"In secondo luogo, osserva il metodo di ricerca. Puoi utilizzare questo metodo per saltare all'interno del file e modificare la posizione del cursore per l'operazione di lettura/scrittura corrente. Quando un file viene aperto per la prima volta, il cursore è impostato sullo 0° byte. Oppure, più precisamente, prima dello zeroesimo byte."

"Ho capito bene? Apriamo il file e il cursore si trova proprio all'inizio, nella posizione 0. Quindi chiamiamo seek e spostiamo il cursore al centesimo byte. E quando chiamiamo readLine , inizia a leggere dal centesimo byte . Giusto?"

"Sì. Ma voglio attirare la tua attenzione sul fatto che il metodo di ricerca ti consente di saltare arbitrariamente all'interno del file. Ad esempio:"

Leggere un file:
// 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();

"In questo esempio, prima leggiamo una riga che inizia dal byte 0. Quindi saltiamo al centesimo byte e leggiamo una riga lì. Quindi saltiamo di nuovo allo 0 byte e leggiamo una riga. Ciò significa che testo1 e testo3 sono identici stringhe."

"Ah. Questo rende le cose più chiare."

"Fantastico. Allora ecco un altro esempio:"

Leggere un file:
// 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();

"Qui apriamo il file per la lettura e la scrittura passando « rw » ( read/write ) al costruttore."

"Poi scriviamo « È una stringa » nel file.

"Quindi spostiamo il cursore sull'ottavo byte (che risulta essere l'inizio della parola 'stringa')"

"Poi scriviamo « sorpresa !»"

"Di conseguenza, il file contiene « È una sorpresa !»"

"Quindi, i byte non vengono inseriti nel mezzo del file, ma piuttosto sostituiscono quelli che c'erano?"

"Sì."

"E se spostiamo il cursore fino alla fine del file?"

"Quindi i byte verranno scritti fino alla fine e il file diventerà più grande. Quindi sarebbe quasi come scrivere del testo in un editor di testo."

"Hmm. Penso di aver capito tutto. Potresti fornire un elenco completo dei metodi della classe RandomAccessFile ?"

"Certo, ecco a te:"

Metodo Descrizione
int read() Legge un byte e lo restituisce
int read(byte b[], int off, int len) Legge un array di byte
int read(byte b[]) Legge un array di byte
void readFully(byte b[]) Legge un array di byte e attende l'aggiunta di nuovi byte se non ce ne sono abbastanza per riempire l'array
int skipBytes(int n) Salta n byte. In altre parole, questo sposta il cursore in avanti di n byte.
void write(int b) Scrive un byte nella posizione del cursore
void write(byte b[]) Scrive una matrice di byte nella posizione del cursore
void write(byte b[], int off, int len) Scrive una matrice di byte nella posizione del cursore
long getFilePointer() Restituisce il numero del byte a cui punta il cursore. Può variare da 0 alla lunghezza del file
void seek(long pos) Sposta il «cursore» utilizzato per la lettura/scrittura nella posizione specificata
long length() Restituisce la lunghezza del file
void setLength(long newLength) Imposta una nuova lunghezza del file. Se il file era più grande, viene troncato; se era più piccolo, espande il file e riempie il nuovo spazio con zeri
void close() Chiude il file
boolean readBoolean() Legge un valore booleano dalla posizione corrente del cursore nel file
byte readByte() Legge un byte dalla posizione corrente del cursore nel file
char readChar() Legge un carattere dalla posizione corrente del cursore nel file
int readInt() Legge un int dalla posizione corrente del cursore nel file
long readLong() Legge un long dalla posizione corrente del cursore nel file
float readFloat() Legge un float dalla posizione corrente del cursore nel file
double readDouble() Legge un double dalla posizione corrente del cursore nel file
String readLine() Legge una riga dal file e la restituisce
void writeBoolean(boolean v) Scrive un valore booleano nel file (a partire dalla posizione del cursore)
void writeByte(int v) t Scrive un byte nel file (a partire dalla posizione del cursore)
void writeChar(int v) Scrive un carattere nel file (partendo dalla posizione del cursore)
void writeInt(int v) Scrive un int nel file (a partire dalla posizione del cursore)
void writeLong(long v) Scrive un lungo nel file (a partire dalla posizione del cursore)
void writeFloat(float v) Scrive un float nel file (a partire dalla posizione del cursore)
void writeDouble(double v) Scrive un double nel file (partendo dalla posizione del cursore)
void writeBytes(String s) Scrive una stringa nel file (a partire dalla posizione del cursore)
void writeChars(String s) Scrive una stringa nel file (a partire dalla posizione del cursore)

"Hmm. Quindi, non c'è niente di nuovo qui. Tranne forse le coppie di metodi seek()/getFilePointer() e length()/setLength()."

"Sì, Amigo. Tutto è più o meno uguale. Ma non è conveniente?"

"È conveniente. Grazie, Bilaabo, per l'interessante lezione e per gli esempi che mi hai fornito."

"Lieto di aiutarti, Amigo, amico mio!"