NIO編程---緩沖區(qū)

**版權(quán)聲明:本文為小斑馬偉原創(chuàng)文章,轉(zhuǎn)載請注明出處!
緩沖區(qū)(Buffer):一個用于特定基本數(shù)據(jù)類型的容器。由java.nio 包定義的,所有緩沖區(qū)都是Buffer 抽象類的子類。Java NIO中的Buffer 主要用于與NIO 通道進(jìn)行交互,數(shù)據(jù)是從通道讀入緩沖區(qū),從緩沖區(qū)寫入通道中的。
Buffer 就像一個數(shù)組,可以保存多個相同類型的數(shù)據(jù)。根據(jù)數(shù)據(jù)類型不同(boolean 除外) ,有以下Buffer 常用子類:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
上述Buffer 類他們都采用相似的方法進(jìn)行管理數(shù)據(jù),只是各自管理的數(shù)據(jù)類型不同而已。都是通過如下方法獲取一個Buffer 對象:
static XxxBuffer allocate(int capacity) : 創(chuàng)建一個容量為capacity 的XxxBuffer 對象
緩沖區(qū)的基本屬性

  • 1 容量(capacity) :表示Buffer 最大數(shù)據(jù)容量,緩沖區(qū)容量不能為負(fù),并且創(chuàng)建后不能更改。
  • 2 限制(limit):第一個不應(yīng)該讀取或?qū)懭氲臄?shù)據(jù)的索引,即位于limit 后的數(shù)據(jù)不可讀寫。緩沖區(qū)的限制不能為負(fù),并且不能大于其容量。
  • 3 位置(position):下一個要讀取或?qū)懭氲臄?shù)據(jù)的索引。緩沖區(qū)的位置不能為負(fù),并且不能大于其限制。
  • 4 標(biāo)記(mark)與重置(reset):標(biāo)記是一個索引,通過Buffer 中的mark() 方法指定Buffer 中一個特定的position,之后可以通過調(diào)用reset() 方法恢復(fù)到這個position。
    標(biāo)記、位置、限制、容量遵守以下不變式:0<=mark<=position<=limit<=capacity

Buffer 的常用方法


緩沖區(qū)的數(shù)據(jù)操作
Buffer 所有子類提供了兩個用于數(shù)據(jù)操作的方法:get() 與put() 方法

  • 1 獲取Buffer 中的數(shù)據(jù)
    get() :讀取單個字節(jié)
    get(byte[] dst):批量讀取多個字節(jié)到dst 中
    get(int index):讀取指定索引位置的字節(jié)(不會移動position)

  • 2 放入數(shù)據(jù)到Buffer 中
    put(byte b):將給定單個字節(jié)寫入緩沖區(qū)的當(dāng)前位置
    put(byte[] src):將src 中的字節(jié)寫入緩沖區(qū)的當(dāng)前位置
    put(int index, byte b):將指定字節(jié)寫入緩沖區(qū)的索引位置(不會移動position)

    @Test
    public void test1(){
      String str = "abcde";
      
      //1. 分配一個指定大小的緩沖區(qū)
      ByteBuffer buf = ByteBuffer.allocate(1024);
      
      System.out.println("-----------------allocate()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      //2. 利用 put() 存入數(shù)據(jù)到緩沖區(qū)中
      buf.put(str.getBytes());
      
      System.out.println("-----------------put()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      //3. 切換讀取數(shù)據(jù)模式
      buf.flip();
      
      System.out.println("-----------------flip()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      //4. 利用 get() 讀取緩沖區(qū)中的數(shù)據(jù)
      byte[] dst = new byte[buf.limit()];
      buf.get(dst);
      System.out.println(new String(dst, 0, dst.length));
      
      System.out.println("-----------------get()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      //5. rewind() : 可重復(fù)讀
      buf.rewind();
      
      System.out.println("-----------------rewind()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      //6. clear() : 清空緩沖區(qū). 但是緩沖區(qū)中的數(shù)據(jù)依然存在,但是處于“被遺忘”狀態(tài)
      buf.clear();
      
      System.out.println("-----------------clear()----------------");
      System.out.println(buf.position());
      System.out.println(buf.limit());
      System.out.println(buf.capacity());
      
      System.out.println((char)buf.get());
      
    }
    
    @Test
     public void test2(){
      String str = "abcde";
      
      ByteBuffer buf = ByteBuffer.allocate(1024);
      
      buf.put(str.getBytes());
      
      //切換讀取數(shù)據(jù)模式
      buf.flip();
      
      byte[] dst = new byte[buf.limit()];
      buf.get(dst, 0, 2);
      System.out.println(new String(dst, 0, 2));
      System.out.println(buf.position());
      
      //mark() : 標(biāo)記
      buf.mark();
      
      buf.get(dst, 2, 2);
      System.out.println(new String(dst, 2, 2));
      System.out.println(buf.position());
      
      //reset() : 恢復(fù)到 mark 的位置
      buf.reset();
      System.out.println(buf.position());
      
      //判斷緩沖區(qū)中是否還有剩余數(shù)據(jù)
      if(buf.hasRemaining()){
          
          //獲取緩沖區(qū)中可以操作的數(shù)量
          System.out.println(buf.remaining());
      }
    }
    

直接與非直接緩沖區(qū):字節(jié)緩沖區(qū)要么是直接的,要么是非直接的。如果為直接字節(jié)緩沖區(qū),則Java 虛擬機(jī)會盡最大努力直接在此緩沖區(qū)上執(zhí)行本機(jī)I/O 操作。也就是說,在每次調(diào)用基礎(chǔ)操作系統(tǒng)的一個本機(jī)I/O 操作之前(或之后),虛擬機(jī)都會盡量避免將緩沖區(qū)的內(nèi)容復(fù)制到中間緩沖區(qū)中(或從中間緩沖區(qū)中復(fù)制內(nèi)容)。
直接字節(jié)緩沖區(qū)可以通過調(diào)用此類的allocateDirect() 工廠方法來創(chuàng)建。此方法返回的緩沖區(qū)進(jìn)行分配和取消分配所需成本通常高于非直接緩沖區(qū)。直接緩沖區(qū)的內(nèi)容可以駐留在常規(guī)的垃圾回收堆之外,因此,它們對應(yīng)用程序的內(nèi)存需求量造成的影響可能并不明顯。所以,建議將直接緩沖區(qū)主要分配給那些易受基礎(chǔ)系統(tǒng)的本機(jī)I/O 操作影響的大型、持久的緩沖區(qū)。一般情況下,最好僅在直接緩沖區(qū)能在程序性能方面帶來明顯好處時分配它們。
直接字節(jié)緩沖區(qū)還可以通過FileChannel 的map() 方法將文件區(qū)域直接映射到內(nèi)存中來創(chuàng)建。該方法返回MappedByteBuffer。Java 平臺的實(shí)現(xiàn)有助于通過JNI 從本機(jī)代碼創(chuàng)建直接字節(jié)緩沖區(qū)。如果以上這些緩沖區(qū)中的某個緩沖區(qū)實(shí)例指的是不可訪問的內(nèi)存區(qū)域,則試圖訪問該區(qū)域不會更改該緩沖區(qū)的內(nèi)容,并且將會在訪問期間或稍后的某個時間導(dǎo)致拋出不確定的異常。
字節(jié)緩沖區(qū)是直接緩沖區(qū)還是非直接緩沖區(qū)可通過調(diào)用其isDirect()方法來確定。提供此方法是為了能夠在性能關(guān)鍵型代碼中執(zhí)行顯式緩沖區(qū)管理。


 @Test
public void test3(){
    //分配直接緩沖區(qū)
    ByteBuffer buf = ByteBuffer.allocateDirect(1024);
    
    System.out.println(buf.isDirect());
}

直接緩沖區(qū)與非直接緩沖區(qū):

  • 1非直接緩沖區(qū):通過 allocate() 方法分配緩沖區(qū),將緩沖區(qū)建立在 JVM 的內(nèi)存中
  • 2 直接緩沖區(qū):通過 allocateDirect() 方法分配直接緩沖區(qū),將緩沖區(qū)建立在物理內(nèi)存中??梢蕴岣咝?/li>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容