作者:Grey
原文地址:Java IO學習筆記三:MMAP與RandomAccessFile
關於RandomAccessFile
相較於前面提到的BufferedReader/Writer和FileReader/Writer
普通的Reader
和Writer
只能順序讀寫數據,RandomAccessFile
提供了一個獨有的seek
方法,可以修改文件內容的指針,從而可以方便讀取和修改文件中的任意位置。示例:
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import static java.nio.charset.StandardCharsets.UTF_8;
public class TestRandomAccessFile {
public static void main(String[] args) {
String path = "C:\\workspace\\out.txt";
try {
RandomAccessFile randomAccessFile = new RandomAccessFile(path, "rw");
randomAccessFile.write("Hello xxxld".getBytes(UTF_8));
randomAccessFile.seek(6);
randomAccessFile.write("Wor".getBytes(UTF_8));
} catch (Exception e) {
e.printStackTrace();
}
}
}
seek(6)
讓指針跳到"Hello xxld"這個字符串中的第一個"x"的位置,再次寫入"Wor"這個字符串(覆蓋寫)
所以返回的結果是:
Hello World
關於MMAP
關於mmap,可以參考這篇文章的介紹認真分析mmap:是什么 為什么 怎么用
mmap是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用
read
,write
等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。
通過RandomAccessFile
可以拿到文件的FileChannel
,並做內存映射(底層就是MMAP,因為文件是塊設備,可以來回自由尋址,所以只有FileChannel
才能做內存映射),即:把內核的pagecache和文件的數據地址空間映射起來。
public static void testRandomAccessFileIO() throws Exception {
String path = "C:\\workspace\\out.txt";
byte[] data = "1234567\n".getBytes();
RandomAccessFile file = new RandomAccessFile(path, "rw");
FileChannel channel = file.getChannel();
int size = 4096 * 100;
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
while (size != 0) {
map.put(data);
size -= data.length;
}
map.force();
}
其中
channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
通過mmap生成的且是堆外的和文件映射的內存區域
原先我們的FileWriter
需要通過write
方法才能將數據寫入pagecache,現在只需要通過map.put方法即可。
其中
map.force()
方法就等同於File中的
file.flush()
方法
將內容從主存寫入磁盤中。