最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

NIO深入理解FileChannel使用方法原理

 更新時間:2023年05月09日 14:00:15   作者:林師傅  
這篇文章主要為大家介紹了NIO深入理解FileChannel的源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

前文我們已經了解了NIO的三大核心組件,本篇文章會詳細介紹FileChannel中的使用方法和原理。

FileChannel

FileChannel是對一個文件讀,寫,映射,操作的Channel。FileChannel是線程安全的,可以被多個線程并發(fā)使用。同一個進程中的多個FileChannel看到的同一個文件的視圖是相同的,由于底層操作系統(tǒng)執(zhí)行的緩存和網絡文件系統(tǒng)協(xié)議引起的延遲,不同進程中在同一時間看到的文件視圖可能會不同。

FileChannel的類圖如下,F(xiàn)ileChannel是一個抽象類,它的具體實現(xiàn)是FileChannelImpl。

FileChannel的創(chuàng)建

獲取FileChannel的方式有下面四種

  • FileChannel.open()

直接調用FileChannel的open()方法,傳入Path即可獲得FileChannel

// 直接傳入Path默認是只讀FileChannel
FileChannel fileChannel = FileChannel.open(Path.of("./tmp/linshifu.txt"));
// 和直接傳入Path相比,支持傳入OpenOption數(shù)組
FileChannel channel = FileChannel.open(Path.of("./tmp/linshifu.txt"), StandardOpenOption.WRITE);

OpenOption是一個空接口,我們可以傳入StandardOpenOption枚舉,StandardOpenOption有如下值

public enum StandardOpenOption implements OpenOption {
    // 可讀Channel
    READ,
    // 可寫Channel
    WRITE,
    // 如果Channel是可寫(WRITE)的,緩沖中的數(shù)據(jù)會從文件末尾開始寫,而不是從頭開始寫
    APPEND,
    // 如果Channel是可寫(WRITE)的,文件的長度會被置為0
    TRUNCATE_EXISTING,
    // 如果文件不存在,則會創(chuàng)建一個新的文件,如果配置了CREATE,則CREATE_NEW會失效
    CREATE,
    // 創(chuàng)建換一個新的文件,如果文件已經存在,則會失敗
    CREATE_NEW,
    // Channel關閉時刪除
    DELETE_ON_CLOSE,
    // 稀疏文件
    SPARSE,
    // 要求對文件內容或元數(shù)據(jù)的每次更新都同步寫入基礎存儲設備。
    SYNC,
    // 要求對文件內容的每次更新都同步寫入基礎存儲設備。
    DSYNC;
}
  • FileInputStream.getChannel()

通過FileInputStream的getChannel()方法獲取FileChannel

FileInputStream fileInputStream = new FileInputStream("./tmp/linshifu.txt");
FileChannel fileChannel = fileInputStream.getChannel();

FileInputStream創(chuàng)建的FileChannel不可寫,只能讀

  • FileOutputStream.getChannel()

通過FileOutputStream的getChannel()方法獲取FileChannel

FileOutputStream fileInputStream = new FileOutputStream("./tmp/linshifu.txt");
FileChannel fileChannel = fileInputStream.getChannel();

FileOutputStream創(chuàng)建FileChannel不可讀,只能寫

  • RandomAccessFile.getChannel()

通過RandomAccessFile的getChannel()方法獲取FileChannel

RandomAccessFile file = new RandomAccessFile("./tmp/linshifu.txt", "rw");
FileChannel fileChannel = file.getChannel();

RandomAccessFile中的模式

與OutputStream和InputStream不同的是創(chuàng)建RandomAccessFile需要傳入模式,RandomAccessFile的模式也會影響到FileChannel,創(chuàng)建RandomAccessFile可以傳入的模式有下面4種

  • r

只讀模式,創(chuàng)建的RandomAccessFile只能讀,如果使用只讀的RandomAccessFile創(chuàng)建的FileChannel寫數(shù)據(jù)會拋出NonWritableChannelException

  • rw

讀寫模式,創(chuàng)建的RandomAccessFile即可讀,也可寫

  • rws

rw一樣,打開以進行讀取和寫入,并且還要求對文件內容或元數(shù)據(jù)的每次更新同步寫入基礎存儲設備

  • rwd

rw一樣,打開以進行讀取和寫入,并且還要求對文件內容的每次更新都同步寫入底層存儲設備

FileChannel操作文件

讀文件操作

讀文件的方法有如下三個

// 從position位置讀取ByteBuffer.capacity個byte,Channel的position向后移動capacity個位置
public abstract int read(ByteBuffer dst) throws IOException;
// 從傳入的position開始讀取ByteBuffer.capacity個byte,Channel的positon位置不變
public abstract int read(ByteBuffer dst, long position) throws IOException;
// 按順序讀取文件到ByteBuffer數(shù)組中,會將數(shù)據(jù)讀取到ByteBuffer數(shù)組的[offset,offset+length)的ByteBuf子數(shù)組中
public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException;

我們準備一個

寫一個demo

寫文件操作

// 從position開始寫入ByteBuffer中的數(shù)據(jù)
public abstract int write(ByteBuffer src) throws IOException;
// 從position開始將ByteBuffer數(shù)組的[offset,offset+length)的ByteBuf子數(shù)組中的數(shù)據(jù)寫入文件
public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException;
// 從position開始將ByteBuffer數(shù)組中的數(shù)據(jù)寫入文件
public final long write(ByteBuffer[] srcs) throws IOException {
    return write(srcs, 0, srcs.length);
}

寫一個Demo

對文件的更新強制輸出到底層存儲設備

這種方式可以確保在系統(tǒng)崩缺時不會丟失數(shù)據(jù),參數(shù)中的boolean表示刷盤時是否將文件元數(shù)據(jù)也同時寫到磁盤上。

public abstract void force(boolean metaData) throws IOException;

通道之間數(shù)據(jù)傳輸

如果需要將FileChannel的數(shù)據(jù)快速傳輸?shù)搅硪粋€Channel,可以使用transferTotransFrom

// 將字節(jié)從此通道的文件傳輸?shù)浇o定的可寫字節(jié)通道
public abstract long transferTo(long position, long count,WritableByteChannel target) throws IOException;
// 將字節(jié)從給定的可讀字節(jié)通道傳輸?shù)酱送ǖ赖奈募?
public abstract long transferFrom(ReadableByteChannel src,long position, long count) throws IOException;

通常情況下我們要將一個通道的數(shù)據(jù)傳到另一個通道。例如,從一個文件讀取數(shù)據(jù)通過socket通道進行發(fā)送。比如通過http協(xié)議讀取服務器上的一個靜態(tài)文件,要經過下面幾個階段

  • 將文件從硬盤拷貝到頁緩沖區(qū)
  • 從頁緩沖區(qū)讀拷貝到用戶緩沖區(qū)
  • 用戶緩沖區(qū)的數(shù)據(jù)拷貝到socket內核緩沖區(qū),最終再將socket內核緩沖區(qū)的數(shù)據(jù)拷貝到網卡中

當我們通過transferTo或者transferFrom在通道之間傳輸數(shù)據(jù)時,如果內核支持,則會使用零拷貝的方式傳輸數(shù)據(jù)

零拷貝技術可以避免將數(shù)據(jù)拷貝到用戶空間中

MappedByteBuffer

MappedByteBuffer是NIO中應對的操作大文件的方式,它的讀寫性能極高,它是一種基于mmap的零拷貝方案,通常情況下可以映射出整個文件,如果文件比較大,也支持分段映射。這其初聽起來似乎不過就是將整個文件讀到內存中,但是事實上并不是這樣。 一般來說,只有文件中實際讀取或者寫入的部分才會映射到內存中。

mmap通過內存映射,將文件映射到內核緩沖區(qū),同時,用戶空間可以共享內核空間的數(shù)據(jù)。這樣在進行網絡傳輸時,就可以減少內核空間到用戶空間的拷貝次數(shù)。mmap需要4次上下文切換,3次數(shù)據(jù)拷貝。

MappedByteBuffer使用的是虛擬內存,因此分配(map)的內存大小不受JVM的-Xmx參數(shù)限制。

MappedByteBuffer使用的方式也比較簡單,首先我們準備一個文件,文件內容如下所示,文件大小34B

我們利用MappedByteBuffer寫一段代碼,將上面文件的第一個字符改成a,代碼如下

public static void main(String[] args) throws Exception {
    RandomAccessFile file = new RandomAccessFile("./tmp/01.txt", "rw");
    MappedByteBuffer mbf = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1024);
    mbf.put(0, (byte) 'a');
    file.close();
}

執(zhí)行完上面代碼之后,這個文件的第一個字符確實被改成了a,但是在文字的末尾也多了很多奇怪的符號

再次查看文件,發(fā)現(xiàn)文件大小變?yōu)榱?KB,我們在進行文件映射時應當注意文件的position和size不應當超出文件的范圍,否則可能導致"文件空洞",磁盤上物理文件中寫入數(shù)據(jù)間產生間隙。

以上就是NIO深入理解FileChannel的詳細內容,更多關于NIO深入理解FileChannel的資料請關注腳本之家其它相關文章!

相關文章

  • Springboot整合Spring Cloud Kubernetes讀取ConfigMap支持自動刷新配置的教程

    Springboot整合Spring Cloud Kubernetes讀取ConfigMap支持自動刷新配置的教程

    這篇文章主要介紹了Springboot整合Spring Cloud Kubernetes讀取ConfigMap支持自動刷新配置,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09
  • Java開發(fā)崗位面試被問到嵌套類怎么辦

    Java開發(fā)崗位面試被問到嵌套類怎么辦

    本篇文章主要介紹了深入理解Java嵌套類和內部類,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-07-07
  • 關于@DS注解切換數(shù)據(jù)源失敗的原因實戰(zhàn)記錄

    關于@DS注解切換數(shù)據(jù)源失敗的原因實戰(zhàn)記錄

    項目配置了多個數(shù)據(jù)源,需要使用@DS注解來切換數(shù)據(jù)源,但是卻遇到了問題,下面這篇文章主要給大家介紹了關于@DS注解切換數(shù)據(jù)源失敗原因的相關資料,需要的朋友可以參考下
    2023-05-05
  • java生成圖片驗證碼的示例代碼

    java生成圖片驗證碼的示例代碼

    這篇文章主要介紹了java生成圖片驗證碼的示例代碼,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-09-09
  • SpringBoot+Mybatis使用Mapper接口注冊的幾種方式

    SpringBoot+Mybatis使用Mapper接口注冊的幾種方式

    本篇博文中主要介紹是Mapper接口與對應的xml文件如何關聯(lián)的幾種姿勢,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-07-07
  • Java super關鍵字用法實戰(zhàn)案例分析

    Java super關鍵字用法實戰(zhàn)案例分析

    這篇文章主要介紹了Java super關鍵字用法,結合具體案例形式分析了java super關鍵字調用父類構造方法、屬性及方法等相關操作技巧與注意事項,需要的朋友可以參考下
    2019-09-09
  • Springboot?多級緩存設計與實現(xiàn)方案

    Springboot?多級緩存設計與實現(xiàn)方案

    多級緩存是提升高并發(fā)系統(tǒng)性能的關鍵策略之一,它不僅能夠減少系統(tǒng)的響應時間,提高用戶體驗,還能有效降低后端系統(tǒng)的負載,防止系統(tǒng)過載,這篇文章主要介紹了Springboot?多級緩存設計與實現(xiàn),需要的朋友可以參考下
    2024-02-02
  • Java實現(xiàn)任意進制轉換

    Java實現(xiàn)任意進制轉換

    這篇文章主要為大家詳細介紹了Java實現(xiàn)任意進制轉換的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java中的Caffeine加載與驅逐策略詳解

    Java中的Caffeine加載與驅逐策略詳解

    這篇文章主要介紹了Java中的Caffeine加載與驅逐策略詳解,Caffeine是基于Java 8的高性能緩存庫,可提供接近最佳的命中率,Caffeine與ConcurrentMap相應,但是不完全相同,本文主要介紹Caffeine,需要的朋友可以參考下
    2023-10-10
  • JavaSE的類和對象你真的了解嗎

    JavaSE的類和對象你真的了解嗎

    這篇文章主要為大家詳細介紹了JavaSE的類和對象,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03

最新評論

吉隆县| 工布江达县| 盐亭县| 阳西县| 涞源县| 双牌县| 布拖县| 大方县| 钟山县| 湘乡市| 清镇市| 防城港市| 靖州| 吴忠市| 深水埗区| 额济纳旗| 盖州市| 麦盖提县| 论坛| 泽库县| 修文县| 贵溪市| 双城市| 阿勒泰市| 桂林市| 翁牛特旗| 凤庆县| 阿拉善右旗| 吐鲁番市| 漳浦县| 古交市| 乐陵市| 周至县| 平遥县| 辽宁省| 怀集县| 汽车| 庆安县| 井冈山市| 周至县| 宾川县|