"Olá, amigo!"

"Oi, Bilaabo! Como vai a vida?"

"Ótimo. Ontem tentei me livrar de alguns parasitas, mas até agora não tive muito sucesso. E depois tive que passar a noite na lata de lixo de novo."

"Então... está tudo ótimo?"

"Você poderia dizer isso."

"Ótimo. Então, o que você tem para mim hoje?"

"Hoje vou falar sobre a classe RandomAccessFile ."

RandomAccessFile, etc. - 1

"O problema é que FileInputStream e FileOutputStream representam arquivos como fluxos: você só pode ler e gravar neles sequencialmente."

"Isso nem sempre é muito conveniente. Às vezes, você precisa escrever algumas linhas no meio de um arquivo ou ler algumas páginas de texto no final de um arquivo de vários megabytes. Não seria muito eficiente ler todo o arquivo para essas tarefas."

"A classe RandomAccessFile foi criada para resolver esse problema. Você pode usá-la para escrever em qualquer lugar do arquivo, ler dele, bem como ler e gravar no arquivo ao mesmo tempo."

"Que interessante!"

"Sim. É realmente muito conveniente."

"Mas como você lê de um local arbitrário?"

"É tudo muito simples. Imagine que você tem um editor de texto, como o Bloco de Notas, aberto. Ele tem um cursor. Quando você digita algo, o texto é adicionado onde quer que o cursor esteja. A leitura de um arquivo é a mesma. A leitura começa de onde quer que o 'cursor' esteja. Ao ler/escrever, o cursor se move automaticamente."

"Aqui, será melhor mostrar um exemplo:"

Lendo um arquivo:
// 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();

"Neste exemplo, gostaria de chamar sua atenção para duas coisas:"

"Primeiro, a criação do objeto RandomAccessFile . O segundo argumento é a letra r. Isso significa que o arquivo é aberto para leitura ( r - read ). Se você deseja abrir um arquivo para leitura e gravação, deve passar « rw » ao construtor, em vez de apenas « r »."

"Segundo, observe o método de busca. Você pode usar esse método para pular o arquivo e alterar a posição do cursor para a operação de leitura/gravação atual. Quando um arquivo é aberto pela primeira vez, o cursor é definido para o 0º byte. Ou, com mais precisão, antes do byte zero."

"Eu entendi corretamente? Abrimos o arquivo e o cursor está bem no início - na posição 0. Em seguida, chamamos a busca e movemos o cursor para o 100º byte. E quando chamamos readLine , ele começa a ler a partir do centésimo byte . Certo?"

"Sim. Mas quero chamar sua atenção para o fato de que o método de busca permite que você pule arbitrariamente pelo arquivo. Por exemplo:"

Lendo um arquivo:
// 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();

"Neste exemplo, primeiro lemos uma linha começando no 0º byte. Em seguida, pulamos para o centésimo byte e lemos uma linha ali. Em seguida, pulamos para o 0º byte novamente e lemos uma linha. Isso significa que text1 e text3 são idênticos cordas."

"Ah. Isso torna as coisas mais claras."

"Ótimo. Então aqui está outro exemplo:"

Lendo um arquivo:
// 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();

"Aqui abrimos o arquivo para leitura e gravação passando « rw » ( read/write ) para o construtor."

"Então escrevemos « É uma string » no arquivo.

"Em seguida, movemos o cursor para o 8º byte (que é o início da palavra 'string')"

"Então escrevemos « surpresa !»"

"Como resultado, o arquivo contém « É uma surpresa !»"

"Então, os bytes não são inseridos no meio do arquivo, mas substituem os que estavam lá?"

"Sim."

"E se movermos o cursor até o final do arquivo?"

"Então os bytes serão gravados até o final e o arquivo ficará maior. Portanto, seria quase como escrever texto em um editor de texto."

"Hmm. Acho que entendi tudo. Você poderia fornecer uma lista completa dos métodos da classe RandomAccessFile ?"

"Claro. Aqui está:"

Método Descrição
int read() Lê um byte e o retorna
int read(byte b[], int off, int len) Lê um array de bytes
int read(byte b[]) Lê um array de bytes
void readFully(byte b[]) Lê uma matriz de bytes e espera que novos bytes sejam adicionados se não houver o suficiente para preencher a matriz
int skipBytes(int n) Pular n bytes. Em outras palavras, isso move o cursor para frente n bytes.
void write(int b) Grava um byte na localização do cursor
void write(byte b[]) Grava uma matriz de bytes na localização do cursor
void write(byte b[], int off, int len) Grava uma matriz de bytes na localização do cursor
long getFilePointer() Retorna o número do byte para o qual o cursor está apontando. Pode variar de 0 ao tamanho do arquivo
void seek(long pos) Move o «cursor» usado para ler/escrever para o local especificado
long length() Retorna o comprimento do arquivo
void setLength(long newLength) Define um novo tamanho de arquivo. Se o arquivo for maior, ele será truncado; se for menor, expande o arquivo e preenche o novo espaço com zeros
void close() Fecha o arquivo
boolean readBoolean() Lê um booleano da posição atual do cursor no arquivo
byte readByte() Lê um byte da posição atual do cursor no arquivo
char readChar() Lê um caractere da posição atual do cursor no arquivo
int readInt() Lê um int da posição atual do cursor no arquivo
long readLong() Lê um long da posição atual do cursor no arquivo
float readFloat() Lê um float da posição atual do cursor no arquivo
double readDouble() Lê um double da posição atual do cursor no arquivo
String readLine() Lê uma linha do arquivo e a retorna
void writeBoolean(boolean v) Grava um valor booleano no arquivo (começando na posição do cursor)
void writeByte(int v) t Grava um byte no arquivo (começando na posição do cursor)
void writeChar(int v) Escreve um char no arquivo (começando na posição do cursor)
void writeInt(int v) Grava um int no arquivo (começando na posição do cursor)
void writeLong(long v) Grava um long no arquivo (começando na posição do cursor)
void writeFloat(float v) Grava um float no arquivo (começando na posição do cursor)
void writeDouble(double v) Grava um duplo no arquivo (começando na posição do cursor)
void writeBytes(String s) Grava uma String no arquivo (começando na posição do cursor)
void writeChars(String s) Grava uma String no arquivo (começando na posição do cursor)

"Hmm. Então, não há nada de novo aqui. Exceto, talvez, os pares de métodos seek()/getFilePointer() e length()/setLength()."

"Sim, Amigo. Tudo é mais ou menos o mesmo. Mas isso não é conveniente?"

"É conveniente. Obrigado, Bilaabo, por uma lição interessante e pelos exemplos que você me deu."

"Fico feliz em ajudar, Amigo, meu amigo!"