1. 程式人生 > 其它 >Java IO學習筆記三:MMAP與RandomAccessFile

Java IO學習筆記三:MMAP與RandomAccessFile

作者: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()

方法

將內容從主存寫入磁碟中。

原始碼

Github