"Hi, Amigo!"

"Hi, Bilaabo! How's life?"

"Great. Yesterday, I tried getting rid of some parasites, but so far I haven't had much success. And then I had to spend the night in the garbage can again."

"So... is everything still great?"

"You could say that."

"Good. So what do you have for me today?"

"Today I will tell you about the RandomAccessFile class."

RandomAccessFile, etc. - 1

"The thing is, FileInputStream and FileOutputStream represent files as streams: you can only read and write to them sequentially."

"That's not always super convenient. Sometimes you need to write a couple of lines in the middle of a file, or read a couple of pages of text from the end of a multi-megabyte file. It wouldn't be very efficient to read the whole file for these tasks."

"The RandomAccessFile class was created to solve this problem. You can use it to write anywhere in the file, read from it, as well as read and write to the file at the same time."

"How interesting!"

"Yep. It's actually quite convenient."

"But how do you read from an arbitrary location?"

"It's all pretty simple. Imagine that you have a text editor, such as Notepad, open. It has a cursor. When you type something, the text is added to wherever the cursor is. Reading a file is the same. Reading starts from wherever the 'cursor' is. When reading/writing, the cursor moves automatically."

"Here, it'll be better to show you an example:"

Reading a 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 this example, I'd like to draw your attention to two things:"

"First, the creation of the RandomAccessFile object. The second argument is the letter r. This means that the file is opened for reading (r - read). If you want to open a file for reading and writing, you must pass «rw» to the constructor, instead of just «r»."

"Second, look at the seek method. You can use this method to jump around the file and change the cursor position for the current read/write operation. When a file is first opened, the cursor is set to the 0th byte. Or, more accurately, before the zeroth byte."

"Did I understand correctly? We open the file, and the cursor is at the very beginning — at position 0. Then we call seek and move the cursor to the 100th byte. And when we call readLine, it starts reading from the hundredth byte. Right?"

"Yes. But I want to draw your attention to the fact that the seek method allows you to jump arbitrarily around the file. For example:"

Reading a 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 this example, we first read a line starting at the 0th byte. Then we jump to the hundredth byte and read a line there. Then we jumped to the 0th byte again and read a line. That means that text1 and text3 are identical strings."

"Ah. That makes things clearer."

"Great. Then here's another example:"

Reading a 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();

"Here we open the file for reading and writing by passing «rw» (read/write) to the constructor."

"Then we write «It is a string» to the file.

"Then we move the cursor to the 8th byte (which happens to be the beginning of the word 'string')"

"Then we write «surprise!»"

"As a result, the file contains «It is a surprise!»"

"So, bytes are not inserted into the middle of the file, but rather they replace the ones that were there?"

"Yep."

"What if we move the cursor to the very end of the file?"

"Then the bytes will be written to the end, and the file will get larger. So it would be almost like writing text into a text editor."

"Hmm. I think I understand everything. Could you provide a complete list of the RandomAccessFile class's methods?"

"Sure. Here you go:"

Method Description
int read() Reads one byte and returns it
int read(byte b[], int off, int len) Reads an array of bytes
int read(byte b[]) Reads an array of bytes
void readFully(byte b[]) Reads an array of bytes, and waits for new bytes to be added if there are not enough of them to fill the array
int skipBytes(int n) Skip n bytes. In other words, this moves the cursor forward n bytes.
void write(int b) Writes one byte to the cursor's location
void write(byte b[]) Writes an array of bytes to the cursor's location
void write(byte b[], int off, int len) Writes an array of bytes to the cursor's location
long getFilePointer() Returns the number of the byte that the cursor is pointing to. It can range from 0 to the file length
void seek(long pos) Moves the «cursor» used for reading/writing to the specified location
long length() Returns the file length
void setLength(long newLength) Sets a new file length. If the file was larger, it gets truncated; if it was smaller, then it expands the file and fills in the new space with zeros
void close() Closes the file
boolean readBoolean() Reads a boolean from the cursor's current position in the file
byte readByte() Reads a byte from the cursor's current position in the file
char readChar() Reads a char from the cursor's current position in the file
int readInt() Reads an int from the cursor's current position in the file
long readLong() Reads a long from the cursor's current position in the file
float readFloat() Reads a float from the cursor's current position in the file
double readDouble() Reads a double from the cursor's current position in the file
String readLine() Reads a line from the file and returns it
void writeBoolean(boolean v) Writes a boolean to the file (starting from the cursor's position)
void writeByte(int v) t Writes a byte to the file (starting from the cursor's position)
void writeChar(int v) Writes a char to the file (starting from the cursor's position)
void writeInt(int v) Writes an int to the file (starting from the cursor's position)
void writeLong(long v) Writes a long to the file (starting from the cursor's position)
void writeFloat(float v) Writes a float to the file (starting from the cursor's position)
void writeDouble(double v) Writes a double to the file (starting from the cursor's position)
void writeBytes(String s) Writes a String to the file (starting from the cursor's position)
void writeChars(String s) Writes a String to the file (starting from the cursor's position)

"Hmm. So, there's nothing new here. Except maybe the seek()/getFilePointer() and length()/setLength() method pairs."

"Yes, Amigo. Everything is about the same. But isn't that convenient?"

"It is convenient. Thank you, Bilaabo, for an interesting lesson and for the examples you gave me."

"Glad to help, Amigo, my friend!"