一 Buffer(緩沖區(qū))介紹
1.1Buffer本質(zhì)上就是一塊內(nèi)存區(qū),可以用來(lái)寫(xiě)入數(shù)據(jù)章咧,并在稍后讀取出來(lái)倦西。這塊內(nèi)存被NIO Buffer包裹起來(lái),對(duì)外提供一系列的讀寫(xiě)方便開(kāi)發(fā)的接口赁严。
在Java NIO中使用的核心緩沖區(qū)如下(覆蓋了通過(guò)I/O發(fā)送的基本數(shù)據(jù)類型:byte, char扰柠、short, int, long, float, double ,long):
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
FloatBuffer
DoubleBuffer
LongBuffer
1.2利用Buffer讀寫(xiě)數(shù)據(jù)疼约,通常遵循四個(gè)步驟:
把數(shù)據(jù)寫(xiě)入buffer卤档;
調(diào)用flip;
從Buffer中讀取數(shù)據(jù)程剥;
調(diào)用buffer.clear()或者buffer.compact()劝枣。
當(dāng)寫(xiě)入數(shù)據(jù)到buffer中時(shí),buffer會(huì)記錄已經(jīng)寫(xiě)入的數(shù)據(jù)大小。當(dāng)需要讀數(shù)據(jù)時(shí)舔腾,通過(guò)flip()方法把buffer從寫(xiě)模式調(diào)整為讀模式溪胶;在讀模式下,可以讀取所有已經(jīng)寫(xiě)入的數(shù)據(jù)稳诚。
當(dāng)讀取完數(shù)據(jù)后哗脖,需要清空buffer,以滿足后續(xù)寫(xiě)入操作扳还。清空buffer有兩種方式:調(diào)用clear()或compact()方法才避。clear會(huì)清空整個(gè)buffer,compact則只清空已讀取的數(shù)據(jù)氨距,未被讀取的數(shù)據(jù)會(huì)被移動(dòng)到buffer的開(kāi)始位置桑逝,寫(xiě)入位置則近跟著未讀數(shù)據(jù)之后。
1.3Buffer的容量衔蹲,位置肢娘,上限(Buffer Capacity, Position and Limit)
這塊內(nèi)存被NIO Buffer管理,并提供一系列的方法用于更簡(jiǎn)單的操作這塊內(nèi)存舆驶。
一個(gè)Buffer有三個(gè)屬性是必須掌握的橱健,分別是:
capacity容量??position位置??limit限制
position和limit的具體含義取決于當(dāng)前buffer的模式。capacity在兩種模式下都表示容量沙廉。
讀寫(xiě)模式下position和limit的含義:
容量(Capacity)
作為一塊內(nèi)存拘荡,buffer有一個(gè)固定的大小,叫做capacit(容量)撬陵。也就是最多只能寫(xiě)入容量值得字節(jié)珊皿,整形等數(shù)據(jù)。一旦buffer寫(xiě)滿了就需要清空已讀數(shù)據(jù)以便下次繼續(xù)寫(xiě)入新的數(shù)據(jù)巨税。
位置(Position)
當(dāng)寫(xiě)入數(shù)據(jù)到Buffer的時(shí)候需要從一個(gè)確定的位置開(kāi)始蟋定,默認(rèn)初始化時(shí)這個(gè)位置position為0,一旦寫(xiě)入了數(shù)據(jù)比如一個(gè)字節(jié)草添,整形數(shù)據(jù)驶兜,那么position的值就會(huì)指向數(shù)據(jù)之后的一個(gè)單元,position最大可以到capacity-1.
當(dāng)從Buffer讀取數(shù)據(jù)時(shí)远寸,也需要從一個(gè)確定的位置開(kāi)始抄淑。buffer從寫(xiě)入模式變?yōu)樽x取模式時(shí),position會(huì)歸零驰后,每次讀取后肆资,position向后移動(dòng)。
上限(Limit)
在寫(xiě)模式灶芝,limit的含義是我們所能寫(xiě)入的最大數(shù)據(jù)量郑原,它等同于buffer的容量唉韭。
一旦切換到讀模式,limit則代表我們所能讀取的最大數(shù)據(jù)量犯犁,他的值等同于寫(xiě)模式下position的位置纽哥。換句話說(shuō),您可以讀取與寫(xiě)入數(shù)量相同的字節(jié)數(shù)(限制設(shè)置為寫(xiě)入的字節(jié)數(shù)栖秕,由位置標(biāo)記)。
二 Buffer的常見(jiàn)方法
方法介紹
abstract Object array()返回支持此緩沖區(qū)的數(shù)組 (可選操作)
abstract int arrayOffset()返回該緩沖區(qū)的緩沖區(qū)的第一個(gè)元素的在數(shù)組中的偏移量 (可選操作)
int capacity()返回此緩沖區(qū)的容量
Buffer clear()清除此緩存區(qū)晓避。將position = 0;limit = capacity;mark = -1;
Buffer flip()flip()方法可以吧Buffer從寫(xiě)模式切換到讀模式簇捍。調(diào)用flip方法會(huì)把position歸零,并設(shè)置limit為之前的position的值俏拱。 也就是說(shuō)暑塑,現(xiàn)在position代表的是讀取位置,limit標(biāo)示的是已寫(xiě)入的數(shù)據(jù)位置锅必。
abstract boolean hasArray()告訴這個(gè)緩沖區(qū)是否由可訪問(wèn)的數(shù)組支持
boolean hasRemaining()return position < limit事格,返回是否還有未讀內(nèi)容
abstract boolean isDirect()判斷個(gè)緩沖區(qū)是否為 direct
abstract boolean isReadOnly()判斷告知這個(gè)緩沖區(qū)是否是只讀的
int limit()返回此緩沖區(qū)的限制
Buffer position(int newPosition)設(shè)置這個(gè)緩沖區(qū)的位置
int remaining()return limit - position; 返回limit和position之間相對(duì)位置差
Buffer rewind()把position設(shè)為0,mark設(shè)為-1搞隐,不改變limit的值
Buffer mark()將此緩沖區(qū)的標(biāo)記設(shè)置在其位置
三 Buffer的使用方式/方法介紹
3.1分配緩沖區(qū)(Allocating a Buffer)
為了獲得緩沖區(qū)對(duì)象驹愚,我們必須首先分配一個(gè)緩沖區(qū)。在每個(gè)Buffer類中劣纲,allocate()方法用于分配緩沖區(qū)逢捺。
下面來(lái)看看ByteBuffer分配容量為28字節(jié)的例子:
ByteBuffer buf = ByteBuffer.allocate(28);
下面來(lái)看看另一個(gè)示例:CharBuffer分配空間大小為2048個(gè)字符。
CharBuffer buf = CharBuffer.allocate(2048);
3.2寫(xiě)入數(shù)據(jù)到緩沖區(qū)(Writing Data to a Buffer)
寫(xiě)數(shù)據(jù)到Buffer有兩種方法:
從Channel中寫(xiě)數(shù)據(jù)到Buffer
手動(dòng)寫(xiě)數(shù)據(jù)到Buffer癞季,調(diào)用put方法
下面是一個(gè)實(shí)例劫瞳,演示從Channel寫(xiě)數(shù)據(jù)到Buffer:
int bytesRead = inChannel.read(buf); //read into buffer.
通過(guò)put寫(xiě)數(shù)據(jù):
buf.put(127);
put方法有很多不同版本,對(duì)應(yīng)不同的寫(xiě)數(shù)據(jù)方法绷柒。例如把數(shù)據(jù)寫(xiě)到特定的位置志于,或者把一個(gè)字節(jié)數(shù)據(jù)寫(xiě)入buffer》夏溃看考JavaDoc文檔可以查閱的更多數(shù)據(jù)伺绽。
3.3翻轉(zhuǎn)(flip())
flip()方法可以吧Buffer從寫(xiě)模式切換到讀模式。調(diào)用flip方法會(huì)把position歸零郊楣,并設(shè)置limit為之前的position的值憔恳。 也就是說(shuō),現(xiàn)在position代表的是讀取位置净蚤,limit標(biāo)示的是已寫(xiě)入的數(shù)據(jù)位置钥组。
從Buffer讀取數(shù)據(jù)(Reading Data from a Buffer)
3.4從Buffer讀數(shù)據(jù)也有兩種方式:
從buffer讀數(shù)據(jù)到channel
從buffer直接讀取數(shù)據(jù),調(diào)用get方法
讀取數(shù)據(jù)到channel的例子:
int bytesWritten = inChannel.write(buf);
調(diào)用get讀取數(shù)據(jù)的例子:
byte aByte = buf.get();
get也有諸多版本今瀑,對(duì)應(yīng)了不同的讀取方式程梦。
3.5 rewind()
Buffer.rewind()方法將position置為0点把,這樣我們可以重復(fù)讀取buffer中的數(shù)據(jù)。limit保持不變屿附。
3.6 clear() and compact()
一旦我們從buffer中讀取完數(shù)據(jù)郎逃,需要復(fù)用buffer為下次寫(xiě)數(shù)據(jù)做準(zhǔn)備。只需要調(diào)用clear()或compact()方法挺份。
如果調(diào)用的是clear()方法褒翰,position將被設(shè)回0,limit被設(shè)置成 capacity的值匀泊。換句話說(shuō)优训,Buffer 被清空了。Buffer中的數(shù)據(jù)并未清除各聘,只是這些標(biāo)記告訴我們可以從哪里開(kāi)始往Buffer里寫(xiě)數(shù)據(jù)揣非。
如果Buffer還有一些數(shù)據(jù)沒(méi)有讀取完,調(diào)用clear就會(huì)導(dǎo)致這部分?jǐn)?shù)據(jù)被“遺忘”躲因,因?yàn)槲覀儧](méi)有標(biāo)記這部分?jǐn)?shù)據(jù)未讀早敬。
針對(duì)這種情況,如果需要保留未讀數(shù)據(jù)大脉,那么可以使用compact搞监。 因此compact()和clear()的區(qū)別就在于:對(duì)未讀數(shù)據(jù)的處理,是保留這部分?jǐn)?shù)據(jù)還是一起清空箱靴。
3.7 mark()與reset()方法
通過(guò)調(diào)用Buffer.mark()方法腺逛,可以標(biāo)記Buffer中的一個(gè)特定position。之后可以通過(guò)調(diào)用Buffer.reset()方法恢復(fù)到這個(gè)position衡怀。例如:
buffer.mark();
//call buffer.get() a couple of times, e.g. during parsing.
buffer.reset(); ?//set position back to mark. ? ?
3.8 equals() and compareTo()
可以用eqauls和compareTo比較兩個(gè)buffer
equals():
判斷兩個(gè)buffer相對(duì)棍矛,需滿足:類型相同
buffer中剩余字節(jié)數(shù)相同,所有剩余字節(jié)相等
從上面的三個(gè)條件可以看出,equals只比較buffer中的部分內(nèi)容抛杨,并不會(huì)去比較每一個(gè)元素够委。
compareTo():
compareTo也是比較buffer中的剩余元素,只不過(guò)這個(gè)方法適用于比較排序的:
四 Buffer常用方法測(cè)試
這里以ByteBuffer為例子說(shuō)明抽象類Buffer的實(shí)現(xiàn)類的一些常見(jiàn)方法的使用: