Mục lục
Sử dụng InputStream, OutputStream, Reader và Writer có một hạn chế là chỉ cho phép đọc ghi dữ liệu tuần tự, vị trí bắt đầu đọc ghi ở đầu tập tin. Vì vậy Java cung cấp RandomAccessFile cho phép chúng ta đọc ghi dữ liệu ngẫu nhiên ở bất kỳ vị trí nào của tập tin.
Khởi tạo RandomAccessFile
Để khởi tạo RandomAccessFile chúng ta có 2 constructor sau
public RandomAccessFile(String name, String mode) RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r");
public RandomAccessFile(File file, String mode) RandomAccessFile randomAccessFile = new RandomAccessFile(new File("/Users/nguyenthanhhai/Desktop/test.txt"), "rw");
Tham số mode để chỉ định các quyền chúng ta có thể thao tác với tập tin, ví dụ r – chỉ đọc, rw – đọc ghi.
Danh sách các mode:
- r – chỉ đọc, nếu gọi write() method ở mode này thì chúng sẽ bị ném IOException.
- rw – đọc và ghi.
- rwd – đọc ghi đồng bộ. Tất cả các thay đổi sẽ được ghi xuống ổ đĩa đồng bộ.
- rws – đọc ghi đồng bộ. Tất cả các thay đổi kể cả siêu dữ liệu sẽ được ghi xuống ổ đĩa đồng bộ.
Đọc file sử dụng RamDomAccessFile
RamdomAccessFile cung cấp hầu hết các method đọc file giúp chúng ta thao tác thuận tiện hơn.
Các hàm hỗ trợ đọc dữ liệu nguyên thuỷ: read(), readInt(), readByte(), readDouble(), readFloat(), readChar(), readLong(), etc.
import java.io.*; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r"); int data; while(( data= randomAccessFile.read()) != -1) { System.out.print((char)data); } randomAccessFile.close(); } }
Sử dụng readLine() để đọc từng dòng trong RandomAccessFile.
import java.io.*; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r"); String line = randomAccessFile.readLine(); while(line != null) { System.out.println("Line: " + line); line = randomAccessFile.readLine(); } randomAccessFile.close(); } }
Ngoài ra chúng ta có thể đọc dữ liệu vào một mảng byte với read(byte[] b) và read(byte[] b, int off, int len).
Note: 2 method read() trên trả về số byte đọc được từ tập tin hoặc -1 nếu đã đọc đến cuối tập tin.
import java.io.IOException; import java.io.RandomAccessFile; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r"); byte[] data = new byte[100]; int bytes = randomAccessFile.read(data); for(int i = 0; i < bytes; i++) { System.out.print((char)data[i]); } randomAccessFile.close(); } }
Lấy độ dài của file
Sử dụng length() method để lấy độ dài của file(đơn vị byte), hay nói cách khác length() trả về số byte mà chúng ta có thể đọc được.
import java.io.IOException; import java.io.RandomAccessFile; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r"); System.out.println("Length: " + randomAccessFile.length()); randomAccessFile.close(); } }
Lấy vị trí con trỏ trong RandomAccessFile
Vị trí con trỏ trong RandomAccessFile object cho biết rằng chúng ta đang nằm ở vị trí nào trong tập tin. Ví dụ đầu tiên nó sẽ nằm ở đầu file có index = 5. Nếu bạn gọi read() method thì nó sẽ trả về byte tại index = 0 và di chuyển con trỏ qua vị trí 1.
import java.io.IOException; import java.io.RandomAccessFile; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "rw"); System.out.println("Pointer before read: " + randomAccessFile.getFilePointer()); randomAccessFile.read(); System.out.println("Pointer after read: " + randomAccessFile.getFilePointer()); randomAccessFile.close(); } }
Đọc file tại một vị trí ngẫu nhiên
seek() method giúp chúng ta dịch chuyển con trỏ đến bất kỳ vị trí nào của file. Ví dụ mình sẽ đọc 10 byte cuối của file text.
import java.io.IOException; import java.io.RandomAccessFile; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "r"); randomAccessFile.seek(randomAccessFile.length() - 10); System.out.println("position: " + randomAccessFile.getFilePointer()); //read last 10 bytes byte db[] = new byte[10]; randomAccessFile.read(db); System.out.println("content: " + new String(db)); randomAccessFile.close(); } }
Ghi file trong RandomAccessFile
Tương tự như phần đọc file, chúng ta cũng có cá method: write(), writeInt(), writeByte(), writeDouble(), writeFloat(), writeChar(), writeLong(), etc để ghi các dữ liệu kiểu nguyên thuỷ xuống file.
Note:
- Bạn phải chọn mode được quyền ghi file như rw, rwd, rws.
- Dữ liệu sẽ được ghi xuống tại vị trí con trỏ đang đứng.
- Vị trí con trỏ luôn là khi vừa khởi tạo, nếu lúc này chúng ta ghi thì dữ liệu sẽ được ghi ở đầu file.
- Nếu vị trí con trỏ nằm giữa file thì dữ liệu tại đó sẽ bị ghi đè bởi dữ liệu mới.
- Sử dụng seek() để dịch chuyển vị trí con trỏ nếu bạn không muốn dữ liệu bị ghi đè.
Ví dụ mình muốn ghi đè dữ liệu của 4 byte cuối trong file bởi chuỗi “ABCB”.
import java.io.IOException; import java.io.RandomAccessFile; class RandomeAccessFileExample { public static void main(String[] args) throws IOException { RandomAccessFile randomAccessFile = new RandomAccessFile("/Users/nguyenthanhhai/Desktop/test.txt", "rw"); byte[] bytes = {65, 66, 67, 68}; randomAccessFile.seek(randomAccessFile.length() - 4); randomAccessFile.write(bytes); randomAccessFile.close(); } }
Tóm lược
RandomAccessFile cho phép chúng ta đọc ghi ở bất kỳ vị trí nào trong file. Khi sử dụng write() method chú ý kết hợp seek() để dịch chuyển vị trí con trỏ để tránh ghi đè dữ liệu.
Các mode là quan trọng nếu chúng ta không cấp đủ quyền thì khi thực hiện sẽ bị IOException. Nhưng cũng đừng lạm dụng nếu không cần thiết, ví dụ như sử dụng mode rw dể đọc ghi mà bạn không bao giờ ghi file thì thật lãng phí tài nguyên.
Trong thực tế RandomeAccessFile thường được sử dụng với các tập tin có cấu trúc cụ thể mà các lập trình viên biết rõ tại mỗi vị trí của con trỏ giá trị mang ý nghĩa gì. Trong đa số chúng ta thường dùng InputStream, OutputStream, Reader và Writer để đọc ghi dữ liệu tuần tự.
Nguồn tham khảo