"Chào, Amigo!"

"Chào, Bilaabo! Cuộc sống thế nào?"

"Tuyệt. Hôm qua, tôi đã cố gắng loại bỏ một số ký sinh trùng, nhưng cho đến nay tôi vẫn chưa thành công lắm. Và sau đó tôi lại phải qua đêm trong thùng rác."

"Vậy... mọi thứ vẫn ổn chứ?"

"Bạn có thể nói rằng."

"Tốt. Vậy hôm nay anh có gì cho tôi?"

"Hôm nay tôi sẽ nói với các bạn về lớp RandomAccessFile ."

RandomAccessFile, v.v. - 1

"Vấn đề là, FileInputStream và FileOutputStream đại diện cho các tệp dưới dạng luồng: bạn chỉ có thể đọc và ghi chúng một cách tuần tự."

"Điều đó không phải lúc nào cũng thuận tiện. Đôi khi bạn cần viết một vài dòng ở giữa tệp hoặc đọc một vài trang văn bản từ cuối tệp nhiều megabyte. Đọc sẽ không hiệu quả lắm toàn bộ tệp cho các tác vụ này."

" Lớp RandomAccessFile được tạo ra để giải quyết vấn đề này. Bạn có thể sử dụng nó để ghi vào bất kỳ đâu trong tệp, đọc từ tệp cũng như đọc và ghi vào tệp cùng một lúc."

"Thật thú vị!"

"Ừ. Nó thực sự khá tiện lợi."

"Nhưng làm thế nào để bạn đọc từ một vị trí tùy ý?"

"Tất cả đều khá đơn giản. Hãy tưởng tượng rằng bạn có một trình soạn thảo văn bản, chẳng hạn như Notepad, đang mở. Nó có một con trỏ. Khi bạn nhập nội dung nào đó, văn bản sẽ được thêm vào bất kỳ vị trí nào của con trỏ. Việc đọc một tệp cũng giống như vậy. Quá trình đọc bắt đầu từ bất kể 'con trỏ' ở đâu. Khi đọc/viết, con trỏ sẽ tự động di chuyển."

"Ở đây, sẽ tốt hơn nếu cho bạn xem một ví dụ:"

Đọc một tập tin:
// 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();

"Trong ví dụ này, tôi muốn bạn chú ý đến hai điều:"

"Đầu tiên, việc tạo đối tượng RandomAccessFile . Đối số thứ hai là chữ r. Điều này có nghĩa là tệp được mở để đọc ( r - read ). Nếu bạn muốn mở tệp để đọc và ghi, bạn phải vượt qua « rw » vào hàm tạo, thay vì chỉ « r »."

"Thứ hai, hãy xem phương thức tìm kiếm. Bạn có thể sử dụng phương thức này để di chuyển xung quanh tệp và thay đổi vị trí con trỏ cho thao tác đọc/ghi hiện tại. Khi tệp được mở lần đầu tiên, con trỏ được đặt thành byte thứ 0. Hoặc, chính xác hơn, trước byte thứ 0."

"Tôi đã hiểu đúng chưa? Chúng tôi mở tệp và con trỏ ở ngay đầu — ở vị trí 0. Sau đó, chúng tôi gọi tìm kiếm và di chuyển con trỏ đến byte thứ 100. Và khi chúng tôi gọi readLine , nó bắt đầu đọc từ byte thứ một trăm . Phải?"

"Vâng. Nhưng tôi muốn bạn chú ý đến thực tế là phương thức tìm kiếm cho phép bạn nhảy tùy ý xung quanh tệp. Ví dụ:"

Đọc một tập tin:
// 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();

"Trong ví dụ này, đầu tiên chúng tôi đọc một dòng bắt đầu từ byte thứ 0. Sau đó, chúng tôi nhảy đến byte thứ một trăm và đọc một dòng ở đó. Sau đó, chúng tôi lại nhảy đến byte thứ 0 và đọc một dòng. Điều đó có nghĩa là text1 và text3 giống hệt nhau dây."

"À. Điều đó làm cho mọi thứ rõ ràng hơn."

"Tuyệt. Sau đây là một ví dụ khác:"

Đọc một tập tin:
// 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();

"Ở đây chúng tôi mở tệp để đọc và ghi bằng cách chuyển « rw » ( read/write ) cho hàm tạo."

"Sau đó, chúng tôi viết « Đó là một chuỗi » vào tệp.

"Sau đó, chúng tôi di chuyển con trỏ đến byte thứ 8 (tình cờ là phần đầu của từ 'chuỗi')"

"Sau đó, chúng tôi viết « bất ngờ ! »"

"Kết quả là, tập tin có chứa « Thật bất ngờ !»"

"Vì vậy, các byte không được chèn vào giữa tệp, mà chúng thay thế các byte ở đó?"

"Chuẩn rồi."

"Điều gì sẽ xảy ra nếu chúng ta di chuyển con trỏ đến cuối tệp?"

"Sau đó, các byte sẽ được ghi vào cuối và tệp sẽ lớn hơn. Vì vậy, nó sẽ gần giống như viết văn bản vào trình soạn thảo văn bản."

"Hmm. Tôi nghĩ tôi hiểu mọi thứ. Bạn có thể cung cấp danh sách đầy đủ các phương thức của lớp RandomAccessFile không ?"

"Chắc chắn rồi. Đây này:"

Phương pháp Sự miêu tả
int read() Đọc một byte và trả về nó
int read(byte b[], int off, int len) Đọc một mảng byte
int read(byte b[]) Đọc một mảng byte
void readFully(byte b[]) Đọc một mảng byte và đợi các byte mới được thêm vào nếu không có đủ byte để lấp đầy mảng
int skipBytes(int n) Bỏ qua n byte. Nói cách khác, điều này di chuyển con trỏ về phía trước n byte.
void write(int b) Ghi một byte vào vị trí của con trỏ
void write(byte b[]) Ghi một mảng byte vào vị trí của con trỏ
void write(byte b[], int off, int len) Ghi một mảng byte vào vị trí của con trỏ
long getFilePointer() Trả về số byte mà con trỏ đang trỏ tới. Nó có thể nằm trong khoảng từ 0 đến độ dài tệp
void seek(long pos) Di chuyển «con trỏ» được sử dụng để đọc/ghi đến vị trí đã chỉ định
long length() Trả về độ dài tệp
void setLength(long newLength) Đặt độ dài tệp mới. Nếu tệp lớn hơn, tệp sẽ bị cắt bớt; nếu nó nhỏ hơn, thì nó sẽ mở rộng tệp và lấp đầy khoảng trống mới bằng số không
void close() Đóng tệp
boolean readBoolean() Đọc một boolean từ vị trí hiện tại của con trỏ trong tệp
byte readByte() Đọc một byte từ vị trí hiện tại của con trỏ trong tệp
char readChar() Đọc một ký tự từ vị trí hiện tại của con trỏ trong tệp
int readInt() Đọc một int từ vị trí hiện tại của con trỏ trong tệp
long readLong() Đọc một đoạn dài từ vị trí hiện tại của con trỏ trong tệp
float readFloat() Đọc một float từ vị trí hiện tại của con trỏ trong tệp
double readDouble() Đọc một cú đúp từ vị trí hiện tại của con trỏ trong tệp
String readLine() Đọc một dòng từ tệp và trả về nó
void writeBoolean(boolean v) Ghi một boolean vào tệp (bắt đầu từ vị trí của con trỏ)
void writeByte(int v) t Ghi một byte vào tệp (bắt đầu từ vị trí của con trỏ)
void writeChar(int v) Ghi một ký tự vào tệp (bắt đầu từ vị trí của con trỏ)
void writeInt(int v) Ghi một int vào tệp (bắt đầu từ vị trí của con trỏ)
void writeLong(long v) Ghi một đoạn dài vào tệp (bắt đầu từ vị trí của con trỏ)
void writeFloat(float v) Ghi một dấu phẩy vào tệp (bắt đầu từ vị trí của con trỏ)
void writeDouble(double v) Ghi một cú đúp vào tệp (bắt đầu từ vị trí của con trỏ)
void writeBytes(String s) Ghi một Chuỗi vào tệp (bắt đầu từ vị trí của con trỏ)
void writeChars(String s) Ghi một Chuỗi vào tệp (bắt đầu từ vị trí của con trỏ)

"Hmm. Vì vậy, không có gì mới ở đây. Ngoại trừ có thể là các cặp phương thức seek()/getFilePointer() và length()/setLength()."

"Vâng, Amigo. Mọi thứ gần như giống nhau. Nhưng điều đó không thuận tiện sao?"

"Thật tiện lợi. Cảm ơn Bilaabo về một bài học thú vị và những ví dụ bạn đã cho tôi."

"Rất vui được giúp đỡ, Amigo, bạn của tôi!"