Java NIO Buffer

? ?Java NIO Buffer用來進行Channel之間的交互,如之前的文章所述,數(shù)據(jù)是從Channel讀入Buffer,再從Buffer寫入Channel中。

? ?一個Buffer實質(zhì)上就是一個可以寫入數(shù)據(jù)葛圃,然后從中讀出數(shù)據(jù)的內(nèi)存塊,這個內(nèi)存塊被包裝成一個NIO的Buffer對象,這個對象提供了一系列方法來使得處理內(nèi)存塊更加簡單装悲。

基礎(chǔ)的Buffer用法:

? ?使用一個Buffer來讀取和寫入數(shù)據(jù)通常遵循如下四個步驟:

1昏鹃、寫數(shù)據(jù)到Buffer
2、調(diào)用Buffer的flip()方法
3诀诊、從Buffer中讀出數(shù)據(jù)
4洞渤、調(diào)用Buffer的clear()或者compact()方法

? ?當(dāng)寫數(shù)據(jù)到Buffer中時,Buffer會追蹤已經(jīng)寫入的數(shù)據(jù)量属瓣。一旦你要讀取數(shù)據(jù)的時候载迄,你需要通過調(diào)用flip()將Buffer的模式從寫入模式切換為讀取模式。在讀取模式下抡蛙,你可以讀取已寫入到Buffer中的所有數(shù)據(jù)护昧。

? ?一旦你已經(jīng)讀取所有的數(shù)據(jù),你需要清理Buffer來進行再次的寫入粗截。你可以通過兩種方式來實現(xiàn):調(diào)用clear()方法或者調(diào)用compact()方法惋耙。clear()方法清理整個Buffer的的數(shù)據(jù),而compact()方法僅清理已經(jīng)讀取過的數(shù)據(jù)熊昌,未讀取的數(shù)據(jù)將移入Buffer的開始位置绽榛,新寫入的數(shù)據(jù)將追加到未讀取的數(shù)據(jù)后邊。

? ?下面是一個Buffer的用例:

RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
FileChannel inChannel = aFile.getChannel();

//創(chuàng)建容量為48 bytes 的Buffer
ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buf); //讀取數(shù)據(jù)到Buffer中
while (bytesRead != -1) {

  buf.flip();  //切換Buffer為讀取模式

  while(buf.hasRemaining()){
      System.out.print((char) buf.get()); // 每次讀取1byte的數(shù)據(jù)
  }

  buf.clear(); //將Buffer切換為寫入模式
  bytesRead = inChannel.read(buf);
}
aFile.close();

Buffer的容量婿屹、位置和限制(Capacity灭美、Position和Limit)

? ?想要理解一個Buffer是如何工作的,你需要熟悉Buffer的三個屬性:

Capacity
Position
Limit

? ?Position和Limit的含義與Buffer處于讀取狀態(tài)還是寫入狀態(tài)有關(guān)昂利,而Capacity則是無論處于讀取狀態(tài)還是寫入狀態(tài)都是一樣的届腐。
? ?下面是寫入模式和讀取模式下Capacity、Position和Limit的說明:


buffers-modes.png

Capacity

? ?作為一個內(nèi)存塊蜂奸,一個Buffer有一個確定的固定大小犁苏,也稱作capacity。你只能寫入這個大小的byte扩所、long傀顾、char等數(shù)據(jù)。一旦Buffer滿了碌奉,你就需要清理掉才能重新寫入數(shù)據(jù)。

Position

? ?當(dāng)你將數(shù)據(jù)寫入Buffer時寒砖,你是在一個確定的position寫入的赐劣,這個position的初始值是0,當(dāng)一個byte哩都、long等數(shù)據(jù)寫入這個Buffer之后魁兼,這個position也會隨著改變,指向即將要寫入數(shù)據(jù)的位置漠嵌,position的最大值是capacity - 1咐汞。

? ?當(dāng)你從Buffer中讀取數(shù)據(jù)時盖呼,你也要從一個給定的position中讀取,當(dāng)你將一個Buffer從寫入模式切換為讀取模式的時候化撕,這個position就會重置為0几晤,你讀取的數(shù)據(jù)也是從這個position的位置開始讀取,position將指向下一個要讀取的位置植阴。

Limit

? ?在寫入模式下蟹瘾,Buffer的limit就是你可以寫入的最大數(shù)據(jù)限制,在寫入模式下limit與Buffer的capacity相等掠手。
? ?當(dāng)切換為讀取模式的時候憾朴,limit就是你可以讀取的最大數(shù)據(jù)量。因此喷鸽,當(dāng)切換一個Buffer為讀取模式的時候众雷,limit就會被置為寫入模式下的position值。換句話說做祝,你可以讀取跟你寫入一樣多的數(shù)據(jù)量(你可以讀取所有你寫入的數(shù)據(jù))砾省。

Buffer的類型

? ?Java NIO有一些幾種類型:

ByteBuffer
MappedByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
? ?如你所見,這些Buffer類型代表著不同的數(shù)據(jù)類型剖淀。換句話說纯蛾,他們允許你使用這些類型來處理Buffer中的char、short纵隔、int翻诉、long、float和short類型數(shù)據(jù)捌刮。

? ?MappedByteBuffer有點特殊碰煌,我們將在專門的章節(jié)中來介紹。

分配Buffer

? ?為了獲取一個Buffer對象绅作,你首先要分配它芦圾。每個Buffer類有一個allocate()方法來處理分配Buffer。
? ?下面是一個分配一個容量為48byte的ByteBuffer例子俄认。

ByteBuffer buf = ByteBuffer.allocate(48);

? ?下面是一個分配1024個字符空間的CharBuffer例子个少。

CharBuffer buf = CharBuffer.allocate(1024);

寫數(shù)據(jù)到Buffer中

? ?你可以按下面的兩種方法寫數(shù)據(jù)到一個Buffer中:

1、從一個Channel寫數(shù)據(jù)到一個Buffer中
2眯杏、通過Buffer的put()方法將數(shù)據(jù)寫入到該Buffer中

? ?下面是一個將Channel數(shù)據(jù)寫入Buffer的例子:

int byteRead = inChannel.read(buf);

? ?下面是一個通過put()方法寫數(shù)據(jù)到Channel的例子:

buf.put(127);

? ?通過put()方法寫數(shù)據(jù)的還有很多個多態(tài)方法夜焦,更多方法請參考Buffer的Doc文檔

flip()

? ?flip()方法能夠?qū)⒁粋€Buffer從寫入狀態(tài)切換為讀取狀態(tài),調(diào)用flip()方法也會limit重置為position的位置岂贩,將position重置為0茫经。

從Buffer中讀出數(shù)據(jù)

? ?有兩種方式來從一個Buffer中讀取數(shù)據(jù):

1、從Buffer中讀取數(shù)據(jù)到Channel
2、使用Buffer的get()方法讀取該Buffer的數(shù)據(jù)

? ?下面是如何從Buffer中讀取數(shù)據(jù)到Channel的列子:

//從Buffer中讀取數(shù)據(jù)到Channel
int bytesWritten = inChannel.write(buf);

? ?下面是使用Buffer的get()方法讀取Buffer數(shù)據(jù)的例子:

byte aByte = buf.get()

rewind()

? ?Buffer的rewind()方法將position重置為0卸伞,這樣你就可以重新讀取Buffer中的所有數(shù)據(jù)了抹镊。limit保持不變,仍然標(biāo)識為可以從Buffer中可以讀出的元素個數(shù)

clear()和compact()

? ?一旦你讀完Buffer的數(shù)據(jù)后荤傲,你需要將Buffer再次置為準(zhǔn)備寫入的狀態(tài)垮耳,你可以調(diào)用clear()或者compact()方法來完成。

? ?如果你調(diào)用clear()方法弃酌,position將置為0氨菇,limit置為capacity,換句話中就是Buffer被清空了,真實的數(shù)據(jù)未被清空妓湘,只是告訴你數(shù)據(jù)位置的標(biāo)記被初始化了而已查蓉。

? ?如果Buffer中還有為讀取的數(shù)據(jù),如果你調(diào)用了clear()的話榜贴,未讀取的數(shù)據(jù)將會被遺忘豌研,也就是說不再有數(shù)據(jù)來指示哪些數(shù)據(jù)已經(jīng)讀取完,哪些數(shù)據(jù)還未讀取完唬党。

? ?如果Buffer中還有數(shù)據(jù)未讀取完鹃共,而你又想稍后再讀取,但是你要先寫入數(shù)據(jù)的話驶拱,你可以調(diào)用compact()而不是clear()霜浴。

? ?compact()拷貝所有未讀取的數(shù)據(jù)到Buffer的開始位置,然后設(shè)置position為未讀取數(shù)據(jù)之后蓝纲,limit與調(diào)用clear()一樣依然設(shè)置為capacity阴孟。這樣Buffer就切換為寫入模式,而未讀取的數(shù)據(jù)也不會被覆蓋税迷。

mark()和reset()

? ?你可以調(diào)用Buffer.mark()方法在Buffer中設(shè)置一個給定的position為標(biāo)記永丝,之后你就可以通過調(diào)用Buffer.reset()方法重新將position置為標(biāo)記的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()

? ?滿足一下條件的話箭养,兩個Buffer就相等了:

1慕嚷、類型相同(byte、char毕泌、int等)
2喝检、Buffer中剩余相同的數(shù)量的bytes、chars撼泛、int等
3蛇耀、所有剩余的bytes、chars坎弯、int等相同

? ?如你所見,equals僅比較Buffer的部分數(shù)據(jù),而不是它內(nèi)部的每個元素抠忘。實際上撩炊,它只是比較Buffer中的剩余元素。

compareTo()

? ?compareTo()方法比較兩個Buffer中的剩余元素崎脉,如果滿足以下條件拧咳,則認為一個Buffer比另一個"小":

1、Buffer中的第一個元素與另一個Buffer中對應(yīng)的第一個元素比較囚灼,小于另一個Buffer的第一個元素
2骆膝、所有元素都相等,但是第一個Buffer的元素個數(shù)小于另一個Buffer的元素個數(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灶体,一起剝皮案震驚了整個濱河市阅签,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蝎抽,老刑警劉巖政钟,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件大溜,死亡現(xiàn)場離奇詭異摧找,居然都是意外死亡,警方通過查閱死者的電腦和手機枕荞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門瓢宦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碎连,“玉大人,你說我怎么就攤上這事驮履∮阏蓿” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵疲吸,是天一觀的道長座每。 經(jīng)常有香客問我,道長摘悴,這世上最難降的妖魔是什么峭梳? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蹂喻,結(jié)果婚禮上葱椭,老公的妹妹穿的比我還像新娘。我一直安慰自己口四,他們只是感情好孵运,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔓彩,像睡著了一般治笨。 火紅的嫁衣襯著肌膚如雪驳概。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天旷赖,我揣著相機與錄音顺又,去河邊找鬼。 笑死等孵,一個胖子當(dāng)著我的面吹牛稚照,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俯萌,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼果录,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咐熙?” 一聲冷哼從身側(cè)響起弱恒,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糖声,沒想到半個月后斤彼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡蘸泻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年琉苇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悦施。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡并扇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抡诞,到底是詐尸還是另有隱情穷蛹,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布昼汗,位于F島的核電站肴熏,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏顷窒。R本人自食惡果不足惜蛙吏,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望鞋吉。 院中可真熱鬧鸦做,春花似錦、人聲如沸谓着。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赊锚。三九已至治筒,卻和暖如春屉栓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背耸袜。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工系瓢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人句灌。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像欠拾,于是被迫代替她去往敵國和親胰锌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容