Java NIO中的Buffer用于和NIO通道進行交互。如你所知,數(shù)據(jù)是從通道讀入緩沖區(qū)骚烧,從緩沖區(qū)寫入到通道中的顶瞒。
緩沖區(qū)本質(zhì)上是一塊可以寫入數(shù)據(jù)夸政,然后可以從中讀取數(shù)據(jù)的內(nèi)存。這塊內(nèi)存被包裝成NIO Buffer對象榴徐,并提供了一組方法守问,用來方便的訪問該塊內(nèi)存。
Buffer的基本用法
寫入數(shù)據(jù)到Buffer
調(diào)用flip()方法
從Buffer中讀取數(shù)據(jù)
調(diào)用clear()方法或者compact()方法
當(dāng)向buffer寫入數(shù)據(jù)時坑资,buffer會記錄下寫了多少數(shù)據(jù)酪碘。一旦要讀取數(shù)據(jù),需要通過flip()方法將Buffer從寫模式切換到讀模式盐茎。在讀模式下兴垦,可以讀取之前寫入到buffer的所有數(shù)據(jù)。
一旦讀完了所有的數(shù)據(jù),就需要清空緩沖區(qū)探越,讓它可以再次被寫入狡赐。有兩種方式能清空緩沖區(qū):調(diào)用clear()或compact()方法。clear()方法會清空整個緩沖區(qū)钦幔。compact()方法只會清除已經(jīng)讀過的數(shù)據(jù)枕屉。任何未讀的數(shù)據(jù)都被移到緩沖區(qū)的起始處,新寫入的數(shù)據(jù)將放到緩沖區(qū)未讀數(shù)據(jù)的后面鲤氢。
下面是一個使用Buffer的例子:
Buffer的capacity,position和limit
緩沖區(qū)本質(zhì)上是一塊可以寫入數(shù)據(jù)搀擂,然后可以從中讀取數(shù)據(jù)的內(nèi)存。這塊內(nèi)存被包裝成NIO Buffer對象卷玉,并提供了一組方法哨颂,用來方便的訪問該塊內(nèi)存。
為了理解Buffer的工作原理相种,需要熟悉它的三個屬性:
capacity
position
limit
position和limit的含義取決于Buffer處在讀模式還是寫模式威恼。不管Buffer處在什么模式,capacity的含義總是一樣的寝并。
這里有一個關(guān)于capacity箫措,position和limit在讀寫模式中的說明,詳細(xì)的解釋在插圖后面衬潦。
capacity
作為一個內(nèi)存塊斤蔓,Buffer有一個固定的大小值,也叫“capacity”.你只能往里寫capacity個byte镀岛、long附迷,char等類型。一旦Buffer滿了哎媚,需要將其清空(通過讀數(shù)據(jù)或者清除數(shù)據(jù))才能繼續(xù)寫數(shù)據(jù)往里寫數(shù)據(jù)喇伯。
position
當(dāng)你寫數(shù)據(jù)到Buffer中時,position表示當(dāng)前的位置拨与。初始的position值為0.當(dāng)一個byte割捅、long等數(shù)據(jù)寫到Buffer后蕾域, position會向前移動到下一個可插入數(shù)據(jù)的Buffer單元宙橱。position最大可為capacity – 1.
當(dāng)讀取數(shù)據(jù)時憔杨,也是從某個特定位置讀。當(dāng)將Buffer從寫模式切換到讀模式淤毛,position會被重置為0. 當(dāng)從Buffer的position處讀取數(shù)據(jù)時今缚,position向前移動到下一個可讀的位置。
limit
在寫模式下低淡,Buffer的limit表示你最多能往Buffer里寫多少數(shù)據(jù)姓言。 寫模式下瞬项,limit等于Buffer的capacity。
當(dāng)切換Buffer到讀模式時何荚, limit表示你最多能讀到多少數(shù)據(jù)囱淋。因此,當(dāng)切換Buffer到讀模式時餐塘,limit會被設(shè)置成寫模式下的position值妥衣。換句話說,你能讀到之前寫入的所有數(shù)據(jù)(limit被設(shè)置成已寫數(shù)據(jù)的數(shù)量戒傻,這個值在寫模式下就是position)
Buffer的類型
Java NIO 有以下Buffer類型
ByteBuffer
MappedByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
如你所見税手,這些Buffer類型代表了不同的數(shù)據(jù)類型。換句話說需纳,就是可以通過char芦倒,short,int候齿,long,float 或 double類型來操作緩沖區(qū)中的字節(jié)闺属。
MappedByteBuffer 有些特別慌盯,在涉及它的專門章節(jié)中再講。
Buffer的分配
要想獲得一個Buffer對象首先要進行分配掂器。 每一個Buffer類都有一個allocate方法亚皂。
下面是一個分配48字節(jié)capacity的ByteBuffer的例子。
ByteBuffer buf = ByteBuffer.allocate(48);
這是分配一個可存儲1024個字符的CharBuffer:
CharBuffer buf = CharBuffer.allocate(1024);
向Buffer中寫數(shù)據(jù)
寫數(shù)據(jù)到Buffer有兩種方式:
從Channel寫到Buffer国瓮。
通過Buffer的put()方法寫到Buffer里灭必。
從Channel寫到Buffer的例子
int bytesRead = inChannel.read(buf);
//read into buffer.
通過put方法寫B(tài)uffer的例子:
buf.put(127);
put方法有很多版本,允許你以不同的方式把數(shù)據(jù)寫入到Buffer中乃摹。例如禁漓, 寫到一個指定的位置,或者把一個字節(jié)數(shù)組寫入到Buffer孵睬。 更多Buffer實現(xiàn)的細(xì)節(jié)參考JavaDoc播歼。
flip()方法
flip方法將Buffer從寫模式切換到讀模式。調(diào)用flip()方法會將position設(shè)回0掰读,并將limit設(shè)置成之前position的值秘狞。
換句話說,position現(xiàn)在用于標(biāo)記讀的位置蹈集,limit表示之前寫進了多少個byte烁试、char等 —— 現(xiàn)在能讀取多少個byte、char等拢肆。
從Buffer中讀取數(shù)據(jù)
從Buffer中讀取數(shù)據(jù)有兩種方式:
從Buffer讀取數(shù)據(jù)到Channel减响。
使用get()方法從Buffer中讀取數(shù)據(jù)靖诗。
從Buffer讀取數(shù)據(jù)到Channel的例子
//read from buffer into channel.
int bytesWritten = inChannel.write(buf);
使用get()方法從Buffer中讀取數(shù)據(jù)的例子
byte aByte = buf.get();
get方法有很多版本,允許你以不同的方式從Buffer中讀取數(shù)據(jù)辩蛋。例如呻畸,從指定position讀取,或者從Buffer中讀取數(shù)據(jù)到字節(jié)數(shù)組悼院。更多Buffer實現(xiàn)的細(xì)節(jié)參考JavaDoc伤为。
rewind()方法
Buffer.rewind()將position設(shè)回0,所以你可以重讀Buffer中的所有數(shù)據(jù)据途。limit保持不變绞愚,仍然表示能從Buffer中讀取多少個元素(byte、char等)颖医。
clear()與compact()方法
一旦讀完Buffer中的數(shù)據(jù)位衩,需要讓Buffer準(zhǔn)備好再次被寫入∪巯簦可以通過clear()或compact()方法來完成糖驴。
如果調(diào)用的是clear()方法,position將被設(shè)回0佛致,limit被設(shè)置成 capacity的值贮缕。換句話說,Buffer 被清空了俺榆。Buffer中的數(shù)據(jù)并未清除感昼,只是這些標(biāo)記告訴我們可以從哪里開始往Buffer里寫數(shù)據(jù)。
如果Buffer中有一些未讀的數(shù)據(jù)罐脊,調(diào)用clear()方法定嗓,數(shù)據(jù)將“被遺忘”,意味著不再有任何標(biāo)記會告訴你哪些數(shù)據(jù)被讀過萍桌,哪些還沒有宵溅。
如果Buffer中仍有未讀的數(shù)據(jù),且后續(xù)還需要這些數(shù)據(jù)上炎,但是此時想要先先寫些數(shù)據(jù)层玲,那么使用compact()方法。
compact()方法將所有未讀的數(shù)據(jù)拷貝到Buffer起始處反症。然后將position設(shè)到最后一個未讀元素正后面辛块。limit屬性依然像clear()方法一樣,設(shè)置成capacity∏Π現(xiàn)在Buffer準(zhǔn)備好寫數(shù)據(jù)了润绵,但是不會覆蓋未讀的數(shù)據(jù)。
mark()與reset()方法
通過調(diào)用Buffer.mark()方法胞谈,可以標(biāo)記Buffer中的一個特定position尘盼。之后可以通過調(diào)用Buffer.reset()方法恢復(fù)到這個position憨愉。例如:
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset();
//set position back to mark.
equals()與compareTo()方法
可以使用equals()和compareTo()方法兩個Buffer。
equals()
當(dāng)滿足下列條件時卿捎,表示兩個Buffer相等:
有相同的類型(byte配紫、char、int等)午阵。
Buffer中剩余的byte躺孝、char等的個數(shù)相等。
Buffer中所有剩余的byte底桂、char等都相同植袍。
如你所見,equals只是比較Buffer的一部分籽懦,不是每一個在它里面的元素都比較于个。實際上,它只比較Buffer中的剩余元素暮顺。
compareTo()方法
compareTo()方法比較兩個Buffer的剩余元素(byte厅篓、char等), 如果滿足下列條件捶码,則認(rèn)為一個Buffer“小于”另一個Buffer:
第一個不相等的元素小于另一個Buffer中對應(yīng)的元素 羽氮。
所有元素都相等,但第一個Buffer比另一個先耗盡(第一個Buffer的元素個數(shù)比另一個少)宙项。
(譯注:剩余元素是從 position到limit之間的元素)