NIO 之 緩衝區(Buffer)

緩存區是java nio的核心部分,因此必須熟悉它的一些操做。java

實現類型:數組

nio中實現了除布爾型(boolean)外的其餘7種基本數據類型的buffer(ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffe),還有Mappedyteuffer,用於表示內存映射文件緩存

基本用法app

使用Buffer讀寫數據通常遵循如下四個步驟: dom

  • 寫入數據到Buffer
  • 調用flip()方法
  • 從Buffer中讀取數據
  • 調用clear()方法或者compact()方法       

當向buffer寫入數據時,buffer會記錄下寫了多少數據。一旦要讀取數據,須要經過flip()方法將Buffer從寫模式切換到讀模式。在讀模式下,能夠讀取以前寫入到buffer的全部數據。 
一旦讀完了全部的數據,就須要清空緩衝區,讓它能夠再次被寫入。有兩種方式能清空緩衝區:調用clear()或compact()方法。clear()方法會清空整個緩衝區。compact()方法只會清除已經讀過的數據。任何未讀的數據都被移到緩衝區的起始處,新寫入的數據將放到緩衝區未讀數據的後面。this

關鍵屬性spa

  • capacity

    做爲一個內存塊,Buffer有一個固定的大小值,也叫「capacity」.你只能往裏寫capacity個byte、long,char等類型。一旦Buffer滿了,須要將其清空(經過讀數據或者清除數據)才能繼續寫數據往裏寫數據。code

    例子:對象

      把一個緩存區比做一個電影廳,這個電影廳只能容下50名觀衆。50表示這個緩存器的capacityblog

  • position

    當你寫數據到Buffer中時,position表示當前的位置。初始的position值爲0.當一個byte、long等數據寫到Buffer後, position會向後移動到下一個可插入數據的Buffer單元。position最大可爲capacity – 1。 

    例子:

      假設電影院的售票策略是 按順序售票,且每一個影廳的位置從0開始算起,且只有50個位置(0-49),某個場次一共賣了30張票,那麼買到第30張票的觀衆的位置應該是29號,這個位置 對應緩存區的position。

  • limit

  在寫模式下,Buffer的limit表示你最多能往Buffer裏寫多少數據。 寫模式下,limit等於Buffer的capacity。 
  當切換Buffer到讀模式時, limit表示你最多能讀到多少數據。所以,當切換Buffer到讀模式時,limit會被設置成寫模式下的position值。換句話說,你能讀到以前寫入的全部數據(limit被設置成已寫數據的數量,這個值在寫模式下就是position) 

  例子:

    電影院每一個場次開場前,可賣的票數爲對應影廳的座位數(容量),開場後每一個場次所售票數爲實際賣出張數。這裏的開場前售票可理解爲寫模式(write),查看開場後實際買票數可理解爲讀模式(read),每一個影廳容量爲50,在開場前可買票數=影廳容量(limit=capacity)爲50,但這個電影實在是太爛了,結果只賣了10張票,最後檢票入場時,檢驗妹子只檢到了第9個位置(位置從0開始算起)

Buffer的分配 

  國民公共王老頭,最近在某地又搞了個萬da影院,堪稱當地最好的影院,分高中檔,vr,4D,巨幕等等各類類型的影廳,不懂得看熱鬧,懂的看門道,其實呢,這個所謂的牛逼影院也就各地影院的拷貝版,無非就是對每一個影廳進行了一些個性化的定製,做爲一個猿,java猿,對它這種吹牛逼,只能呵呵呵,用面向對象封裝下,全部影廳按着一個有屏幕、座位、音箱、投影儀的標準的影廳結構建造,而後不一樣檔次/類型進行個性化定製。

 偉大的建築工人幫王老頭建造了一座座的萬da影院,做爲一爲低調的碼農,只能默默的用代碼構造一個屬於本身的萬達私人影院了,當上國民爺爺。

 一個標準的影廳結構,對應全部類型緩存區(ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffe,Mappedyteuffer)的父類,

java.nio.Buffer

每一個影廳都有標準影廳結構改造而來,因此每種類型的緩存區都繼承java.nio.Buffer類,偉大的建築師用一個個磚建造每一個影廳,智慧的碼農只需一行代碼就能搞定一個屬於本身的影廳(緩存區),不信往下看

ByteBuffer buf = ByteBuffer.allocate(48);  

牛逼吧,並且座位數能夠隨時增長,只要有地皮(內存空間),能夠隨時增長。更厲害的是,每種類型的影廳(緩存區)均可以哦,並且實現方法都同樣,例如CharBuffer

CharBuffer buf = CharBuffer.allocate(1024);  

Buffer的操做方法

  王老頭你的影廳再牛逼,觀衆也要去跑到影院看,敢不敢爲每一個觀衆配專車接送,一條龍服務...,碼農的私人影院不但建造簡單又快捷,並且服務也是噹噹的,觀衆隨時隨地能夠體驗不一樣類型的影廳,不信你看看。

CharBuffer buf = CharBuffer.allocate(1024);  
buf.put("wanglaotou".toCharArray());

  據說王老頭的影院vip用戶能夠享受專屬vip通道進影廳,哈哈,城會玩。私人影院同樣能夠,接招

RandomAccessFile aFile = null;
        try {
            //找到王老頭的家
            aFile = new RandomAccessFile("F:\\王老頭的家.txt", "rw");
            //走專屬通道
            FileChannel inChannel = aFile.getChannel();  
            //建造專屬影廳
            ByteBuffer buf = ByteBuffer.allocate(48); 
            //請王老頭入座
            int bytesRead = inChannel.read(buf);
            System.out.println("家丁人數:"+bytesRead);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }  catch (IOException e) {
            e.printStackTrace();
        } finally{
            if (aFile!=null) {
                aFile.close();
            }
        }  

據說萬da影院引進了一套先進的檢票系統,不但節約了人力成本還能夠自動統計每場次實際入場人數,因而各大媒體各類吹捧,公民公公再次上頭條,當低調的碼農們聽到

這個消息後,又是呵呵呵,由於他家的私人影院只需兩行代碼就能統計出來。

buf.flip();//統計命令(至關於從寫模式進入到讀模式)
System.out.println("入場人數(輸入長度):"+buf.limit());
flip方法將Buffer從寫模式切換到讀模式。調用flip()方法會將position設回0,並將limit設置成以前position的值。 
換句話說,position如今用於標記讀的位置,limit表示以前寫進了多少個byte、char等 —— 如今能讀取多少個byte、char等。

public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}

其實,就在剛剛接王老頭來看電影的路上出了一個插曲,在路上遇見了他的一位朋友(蒼老師),而後此次正好王老太去歐洲遊不在家,而後司機確認身份後得知是蒼老師,而後就帶上了蒼老師陪他一塊去觀影,肯定身份的過程是這樣的

int bytesWritten = inChannel.write(buf);  

其實,就這樣一行代碼,就把王老頭的這位朋友的身份確認了(從Buffer中讀取數據),哇塞,難道是他的小san?

固然咱們的司機師傅不只會這一招還有其餘的確認身份方法,簡單的向你演示下

byte aByte = buf.get();  

get方法有不少版本,容許你以不一樣的方式從Buffer中讀取數據。例如,從指定position讀取,或者從Buffer中讀取數據到字節數組。更多Buffer實現的細節參考JavaDoc。 

哎呀,實在沒力氣編瞎話了,下面幾個方法,隨便說說吧

rewind()方法 

Buffer.rewind()將position設回0,因此你能夠重讀Buffer中的全部數據。limit保持不變,仍然表示能從Buffer中讀取多少個元素(byte、char等)。 

 public final Buffer rewind() {
        position = 0;
        mark = -1;
        return this;
    }


clear()與compact()方法 

一旦讀完Buffer中的數據,須要讓Buffer準備好再次被寫入。能夠經過clear()或compact()方法來完成。 

若是調用的是clear()方法,position將被設回0,limit被設置成 capacity的值。換句話說,Buffer 被清空了。Buffer中的數據並未清除,只是這些標記告訴咱們能夠從哪裏開始往Buffer裏寫數據。 

若是Buffer中有一些未讀的數據,調用clear()方法,數據將「被遺忘」,意味着再也不有任何標記會告訴你哪些數據被讀過,哪些尚未。 

若是Buffer中仍有未讀的數據,且後續還須要這些數據,可是此時想要先先寫些數據,那麼使用compact()方法。

compact()方法將全部未讀的數據拷貝到Buffer起始處。而後將position設到最後一個未讀元素正後面。limit屬性依然像clear()方法同樣,設置成capacity。如今Buffer準備好寫數據了,可是不會覆蓋未讀的數據。 

  public final Buffer clear() {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }

 


mark()與reset()方法 

經過調用Buffer.mark()方法,能夠標記Buffer中的一個特定position。以後能夠經過調用Buffer.reset()方法恢復到這個position。例如: 

 public final Buffer mark() {
        mark = position;
        return this;
    }

 

equals()與compareTo()方法 

可使用equals()和compareTo()方法兩個Buffer。 

equals() 

當知足下列條件時,表示兩個Buffer相等: 

  • 有相同的類型(byte、char、int等)。
  • Buffer中剩餘的byte、char等的個數相等。
  • Buffer中全部剩餘的byte、char等都相同。


如你所見,equals只是比較Buffer的一部分,不是每個在它裏面的元素都比較。實際上,它只比較Buffer中的剩餘元素。 

compareTo()方法 

compareTo()方法比較兩個Buffer的剩餘元素(byte、char等), 若是知足下列條件,則認爲一個Buffer「小於」另外一個Buffer: 

    • 第一個不相等的元素小於另外一個Buffer中對應的元素。
    • 全部元素都相等,但第一個Buffer比另外一個先耗盡(第一個Buffer的元素個數比另外一個少)。
相關文章
相關標籤/搜索