日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Java Nio FileChannel堆內堆外數據讀寫全流程分析及使用

來源: 責編: 時間:2024-05-27 08:57:11 155觀看
導讀背景java nio中文件讀寫不管是普通文件讀寫,還是基于mmap實現零拷貝,都離不開FileChannel這個類。隨便打開RocketMQ 源碼搜索FileChannel。就可以看到使用頻率。圖片kafka也是。圖片所以在java中文件讀寫FileChannel尤

背景

java nio中文件讀寫不管是普通文件讀寫,還是基于mmap實現零拷貝,都離不開FileChannel這個類。2J328資訊網——每日最新資訊28at.com

隨便打開RocketMQ 源碼搜索FileChannel。2J328資訊網——每日最新資訊28at.com

就可以看到使用頻率。2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

kafka也是。2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

所以在java中文件讀寫FileChannel尤為重用。2J328資訊網——每日最新資訊28at.com

java文件讀寫全流程

圖片圖片2J328資訊網——每日最新資訊28at.com

這里說的僅僅是FileChannel基于堆內存(HeapByteBuffer)的文件讀寫。2J328資訊網——每日最新資訊28at.com

如果是mmap或者堆外內存,可能有些步驟會省略,相當于有一些優化。2J328資訊網——每日最新資訊28at.com

  1. FileChannel調用read,將HeapByteBuffer拷貝到DirectByteBuffer。
  2. JVM在native層使用read系統調用進行文件讀取, 這里需要進行上下文切換,從用戶態進入內核態。
  3. JVM 進程進入虛擬文件系統層,查看文件數據再page cache是否緩存,如果有則直接從page cache讀取并返回到DirectByteBuffer。
  4. 如果請求文件數據不在page caceh,則進入文件系統。通過塊驅動設備進行真正的IO,并進行文件預讀,比如讀取的文件可能只有1-10,但是會將1-20都讀取。
  5. 磁盤控制器DMA將磁盤中的數據拷貝到page cache中。這里發生了一次數據拷貝(非CPU拷貝)。
  6. CPU將page cache數據拷貝到DirectByteBuffer,因為page cache屬于內核空間,JVM進程無法直接尋址。這里是發生第二次數據拷貝。
  7. JVM進程從內核態切換回用戶態,這里如果使用的是堆內存(HeapByteBuffer),實際還需要將堆外內存DirectByteBuffer拷貝到堆內存(HeapByteBuffer)。

FileChannel讀寫文件(非MMAP)

public static void main(String[] args) {        String filename = "小奏技術.txt";        String content = "Hello, 小奏技術.";        // 寫入文件        writeFile(filename, content);        // 讀取文件        System.out.println("Reading from file:");        readFile(filename);    }    public static void writeFile(String filename, String content) {        // 創建文件對象        File file = new File(filename);        // 確保文件存在        if (!file.exists()) {            try {                boolean created = file.createNewFile();                if (!created) {                    System.err.println("Unable to create file: " + filename);                    return;                }            } catch (Exception e) {                System.err.println("An error occurred while creating the file: " + e.getMessage());                return;            }        }        // 使用FileChannel寫入文件        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");             FileChannel fileChannel = randomAccessFile.getChannel()) {            ByteBuffer buffer = ByteBuffer.allocate(content.getBytes().length);            buffer.put(content.getBytes());            buffer.flip(); // 切換到讀模式            while (buffer.hasRemaining()) {                fileChannel.write(buffer);            }        } catch (Exception e) {            System.err.println("An error occurred while writing to the file: " + e.getMessage());        }    }    public static void readFile(String filename) {        // 使用FileChannel讀取文件        try (RandomAccessFile randomAccessFile = new RandomAccessFile(filename, "r");             FileChannel fileChannel = randomAccessFile.getChannel()) {            ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());            while (fileChannel.read(buffer) > 0) {                // Do nothing, just read            }            // 切換到讀模式            buffer.flip();            /* while (buffer.hasRemaining()) {                System.out.print((char) buffer.get());            }*/            Charset charset = StandardCharsets.UTF_8;             String fileContent = charset.decode(buffer).toString();            System.out.print(fileContent);        } catch (Exception e) {            System.err.println("An error occurred while reading the file: " + e.getMessage());        }    }

這里需要注意的一個細節 我們分配的內存的方式是:2J328資訊網——每日最新資訊28at.com

ByteBuffer.allocate()

這里我們可以進入看看源碼:2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

實際構造的是HeapByteBuffer,也就是JVM的堆內存。2J328資訊網——每日最新資訊28at.com

如果我們使用:2J328資訊網——每日最新資訊28at.com

ByteBuffer.allocateDirect()

圖片圖片2J328資訊網——每日最新資訊28at.com

則構造的是堆外內存DirectByteBuffer。2J328資訊網——每日最新資訊28at.com

HeapByteBuffer和DirectByteBuffer文件讀寫區別

我們看看FileChannel read方法:2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

發現IO相關的處理被封裝在IOUtil,我們繼續看看IOUtil的write方法:2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

可以看到如果是DirectBuffer則可以直接寫。如果是HeapByteBuffer則需要轉換為DirectByteBuffer。2J328資訊網——每日最新資訊28at.com

圖片圖片2J328資訊網——每日最新資訊28at.com

為什么要在DirectByteBuffer做一層轉換

主要是HeapByteBuffer受JVM管理,也就是會受到GC影響。如果在進行native調用的時候發生了GC,會導致HeapByteBuffer的內容出現錯誤。具體詳細的說明可以看看這篇MappedByteBuffer VS FileChannel:從內核層面對比兩者的性能差異。講解的非常清晰。2J328資訊網——每日最新資訊28at.com

參考

  • MappedByteBuffer VS FileChannel:從內核層面對比兩者的性能差異 

本文鏈接:http://www.www897cc.com/showinfo-26-90858-0.htmlJava Nio FileChannel堆內堆外數據讀寫全流程分析及使用

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Wire:Go語言依賴注入的利器

下一篇: 避免鎖表:為Update語句中的Where條件添加索引字段

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 即墨市| 渝中区| 龙海市| 苏尼特右旗| 额尔古纳市| 禄劝| 绍兴市| 内丘县| 浦东新区| 乌鲁木齐县| 康平县| 田林县| 兴海县| 清水河县| 阳春市| 门头沟区| 彝良县| 新河县| 玉林市| 开阳县| 九台市| 绥江县| 青冈县| 岢岚县| 襄汾县| 乐平市| 多伦县| 丰城市| 全南县| 墨竹工卡县| 冕宁县| 莒南县| 金寨县| 澄迈县| 乐山市| 临潭县| 旬阳县| 渝中区| 大名县| 渝北区| 公主岭市|