Java NIO Buffer

Java NIO Buffer

Buffer使用場(chǎng)景

Java NIO buffers 用于和Java channels 交互。正如上一節(jié)提及到的從通道中寫(xiě)入緩沖區(qū)或者是從緩沖區(qū)中寫(xiě)入到通道中岛杀。

Java NIO Buffers 本質(zhì)上來(lái)講就是一塊內(nèi)存。這塊內(nèi)存被包裝成NIO Buffers类嗤,并且提供了一組方法,用來(lái)方便的訪問(wèn)該快內(nèi)存遗锣。

Buffer的基本用法

Buffer的用法分為四個(gè)步驟

  • 寫(xiě)入數(shù)據(jù)
  • 調(diào)用flip()切換成讀模式
  • 從buffer中讀取數(shù)據(jù)
  • 調(diào)用buffer.clear()或者是buffer.compact()方法

當(dāng)向buffer寫(xiě)入數(shù)據(jù)時(shí),buffer會(huì)記錄下寫(xiě)了多少數(shù)據(jù)弧圆。一旦要讀取數(shù)據(jù)笔咽,需要通過(guò)flip()方法將Buffer從寫(xiě)模式切換到讀模式。在讀模式下叶组,可以讀取之前寫(xiě)入到buffer的所有數(shù)據(jù)。

一旦讀完了所有的數(shù)據(jù)甩十,就需要清空緩沖區(qū)吭产,讓它可以再次被寫(xiě)入垮刹。有兩種方式能清空緩沖區(qū):調(diào)用clear()或compact()方法。clear()方法會(huì)清空整個(gè)緩沖區(qū)荒典。compact()方法只會(huì)清除已經(jīng)讀過(guò)的數(shù)據(jù)吞鸭。任何未讀的數(shù)據(jù)都被移到緩沖區(qū)的起始處,新寫(xiě)入的數(shù)據(jù)將放到緩沖區(qū)未讀數(shù)據(jù)的后面刻剥。

package com.viashare.buffer;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * Created by Jeffy on 16/5/18.
 */
public class BufferMain {

    final static String PATH = "/Users/jeffy-pc/Downloads/test.txt";

    public static void main(String[] args) throws IOException {
        RandomAccessFile randomAccessFile = new RandomAccessFile(PATH, "rw");
        FileChannel channel = randomAccessFile.getChannel();
        StringBuffer buffer = new StringBuffer();

        ByteBuffer byteBuffer = ByteBuffer.allocate(48);
        int bytesRead = channel.read(byteBuffer);
        while (bytesRead != -1) {
            byteBuffer.flip();
            while (byteBuffer.hasRemaining()) {
//                System.err.println((char) byteBuffer.get());
                buffer.append((char)byteBuffer.get());
            }
            byteBuffer.clear();
            bytesRead = channel.read(byteBuffer);
        }
        System.err.println(buffer.toString());
        randomAccessFile.close();
    }
}

Buffer的capacity,position和limit

緩沖區(qū)本質(zhì)上是一塊可以寫(xiě)入數(shù)據(jù)造虏,然后可以從中讀取數(shù)據(jù)的內(nèi)存。這塊內(nèi)存被包裝成NIO Buffer對(duì)象陶珠,并提供了一組方法,用來(lái)方便的訪問(wèn)該塊內(nèi)存揍诽。

為了理解Buffer的工作原理栗竖,需要熟悉它的三個(gè)屬性:

  • capacity
  • position
  • limit

position和limit的含義取決于Buffer處在讀模式還是寫(xiě)模式。不管Buffer處在什么模式狐肢,capacity的含義總是一樣的。

這里有一個(gè)關(guān)于capacity碟联,position和limit在讀寫(xiě)模式中的說(shuō)明,詳細(xì)的解釋在插圖后面玄帕。

image
  • capacity

作為一個(gè)內(nèi)存塊想邦,Buffer有一個(gè)固定的大小值委刘,也叫“capacity”.你只能往里寫(xiě)capacity個(gè)byte鹰椒、long呕童,char等類(lèi)型。一旦Buffer滿了奸汇,需要將其清空(通過(guò)讀數(shù)據(jù)或者清除數(shù)據(jù))才能繼續(xù)寫(xiě)數(shù)據(jù)往里寫(xiě)數(shù)據(jù)。

  • position

當(dāng)你寫(xiě)數(shù)據(jù)到Buffer中時(shí)擂找,position表示當(dāng)前的位置。初始的position值為0.當(dāng)一個(gè)byte贯涎、long等數(shù)據(jù)寫(xiě)到Buffer后慢洋, position會(huì)向前移動(dòng)到下一個(gè)可插入數(shù)據(jù)的Buffer單元。position最大可為capacity – 1.

當(dāng)讀取數(shù)據(jù)時(shí)普筹,也是從某個(gè)特定位置讀。當(dāng)將Buffer從寫(xiě)模式切換到讀模式肩刃,position會(huì)被重置為0. 當(dāng)從Buffer的position處讀取數(shù)據(jù)時(shí),position向前移動(dòng)到下一個(gè)可讀的位置盈包。

  • limit

在寫(xiě)模式下醇王,Buffer的limit表示你最多能往Buffer里寫(xiě)多少數(shù)據(jù)。 寫(xiě)模式下寓娩,limit等于Buffer的capacity。

當(dāng)切換Buffer到讀模式時(shí)棘伴, limit表示你最多能讀到多少數(shù)據(jù)。因此仁连,當(dāng)切換Buffer到讀模式時(shí),limit會(huì)被設(shè)置成寫(xiě)模式下的position值饭冬。換句話說(shuō),你能讀到之前寫(xiě)入的所有數(shù)據(jù)(limit被設(shè)置成已寫(xiě)數(shù)據(jù)的數(shù)量昌抠,這個(gè)值在寫(xiě)模式下就是position)

Buffer的類(lèi)型

Java NIO 有以下Buffer類(lèi)型

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

如你所見(jiàn),這些Buffer類(lèi)型代表了不同的數(shù)據(jù)類(lèi)型裁厅。換句話說(shuō),就是可以通過(guò)char姐直,short,int声畏,long姻成,float 或 double類(lèi)型來(lái)操作緩沖區(qū)中的字節(jié)。

MappedByteBuffer 有些特別均牢,在涉及它的專(zhuān)門(mén)章節(jié)中再講。

Buffer的分配

要想獲得一個(gè)Buffer對(duì)象首先要進(jìn)行分配徘跪。 每一個(gè)Buffer類(lèi)都有一個(gè)allocate方法。下面是一個(gè)分配48字節(jié)capacity的ByteBuffer的例子垮庐。

CharBuffer buf = CharBuffer.allocate(1024);

向Buffer中寫(xiě)數(shù)據(jù)

寫(xiě)數(shù)據(jù)到Buffer有兩種方式

  • 從Channel寫(xiě)到Buffer坞琴。
  • 通過(guò)Buffer的put()方法寫(xiě)到Buffer里

put方法有很多版本,允許你以不同的方式把數(shù)據(jù)寫(xiě)入到Buffer中寒亥。例如, 寫(xiě)到一個(gè)指定的位置溉奕,或者把一個(gè)字節(jié)數(shù)組寫(xiě)入到Buffer。 更多Buffer實(shí)現(xiàn)的細(xì)節(jié)參考JavaDoc加勤。

  • lip()方法

flip方法將Buffer從寫(xiě)模式切換到讀模式。調(diào)用flip()方法會(huì)將position設(shè)回0欺嗤,并將limit設(shè)置成之前position的值卫枝。

換句話說(shuō),position現(xiàn)在用于標(biāo)記讀的位置校赤,limit表示之前寫(xiě)進(jìn)了多少個(gè)byte、char等 —— 現(xiàn)在能讀取多少個(gè)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實(shí)現(xiàn)的細(xì)節(jié)參考JavaDoc。

  • rewind()方法

Buffer.rewind()將position設(shè)回0逐抑,所以你可以重讀Buffer中的所有數(shù)據(jù)。limit保持不變厕氨,仍然表示能從Buffer中讀取多少個(gè)元素(byte汹粤、char等)。

  • clear()與compact()方法

一旦讀完Buffer中的數(shù)據(jù)嘱兼,需要讓Buffer準(zhǔn)備好再次被寫(xiě)入。可以通過(guò)clear()或compact()方法來(lái)完成接奈。

如果調(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ù),調(diào)用clear()方法澈蝙,數(shù)據(jù)將“被遺忘”,意味著不再有任何標(biāo)記會(huì)告訴你哪些數(shù)據(jù)被讀過(guò)碉克,哪些還沒(méi)有并齐。

如果Buffer中仍有未讀的數(shù)據(jù),且后續(xù)還需要這些數(shù)據(jù)撕贞,但是此時(shí)想要先先寫(xiě)些數(shù)據(jù),那么使用compact()方法捏膨。

compact()方法將所有未讀的數(shù)據(jù)拷貝到Buffer起始處。然后將position設(shè)到最后一個(gè)未讀元素正后面号涯。limit屬性依然像clear()方法一樣锯七,設(shè)置成capacity。現(xiàn)在Buffer準(zhǔn)備好寫(xiě)數(shù)據(jù)了域蜗,但是不會(huì)覆蓋未讀的數(shù)據(jù)巨双。

  • 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.


equals()與compareTo()方法

可以使用equals()和compareTo()方法兩個(gè)Buffer半夷。

  • equals()

當(dāng)滿足下列條件時(shí)迅细,表示兩個(gè)Buffer相等:

  • 有相同的類(lèi)型(byte、char茵典、int等)
  • Buffer中剩余的byte、char等的個(gè)數(shù)相等彩倚。
  • Buffer中所有剩余的byte扶平、char等都相同。

如你所見(jiàn)结澄,equals只是比較Buffer的一部分,不是每一個(gè)在它里面的元素都比較们妥。實(shí)際上,它只比較Buffer中的剩余元素监婶。

  • compareTo()方法

compareTo()方法比較兩個(gè)Buffer的剩余元素(byte齿桃、char等), 如果滿足下列條件短纵,則認(rèn)為一個(gè)Buffer“小于”另一個(gè)Buffer:

  • 第一個(gè)不相等的元素小于另一個(gè)Buffer中對(duì)應(yīng)的元素 。
  • 所有元素都相等刮刑,但第一個(gè)Buffer比另一個(gè)先耗盡(第一個(gè)Buffer的元素個(gè)數(shù)比另一個(gè)少)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末雷绢,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子翘紊,更是在濱河造成了極大的恐慌,老刑警劉巖帆疟,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異自赔,居然都是意外死亡柳琢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)他去,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倒堕,“玉大人灾测,你說(shuō)我怎么就攤上這事垦巴。” “怎么了蛾号?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵鲜结,是天一觀的道長(zhǎng)活逆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蔗候,這世上最難降的妖魔是什么怒允? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮锈遥,結(jié)果婚禮上纫事,老公的妹妹穿的比我還像新娘勘畔。我一直安慰自己,他們只是感情好丽惶,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布炫七。 她就那樣靜靜地躺著,像睡著了一般钾唬。 火紅的嫁衣襯著肌膚如雪万哪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天抡秆,我揣著相機(jī)與錄音,去河邊找鬼儒士。 笑死,一個(gè)胖子當(dāng)著我的面吹牛冲杀,可吹牛的內(nèi)容都是我干的睹酌。 我是一名探鬼主播憋沿,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辐啄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼运嗜!你這毒婦竟也來(lái)了担租?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尝艘,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體秒际,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娄徊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年嵌莉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片中鼠。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡援雇,死狀恐怖惫搏,靈堂內(nèi)的尸體忽然破棺而出蚕涤,到底是詐尸還是另有隱情揖铜,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布贿肩,位于F島的核電站汰规,受9級(jí)特大地震影響溜哮,放射性物質(zhì)發(fā)生泄漏拂封。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一在抛、第九天 我趴在偏房一處隱蔽的房頂上張望刚梭。 院中可真熱鬧,春花似錦屹徘、人聲如沸衅金。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)豆励。三九已至瞒渠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嫩痰,已是汗流浹背始赎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晰搀,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像乡翅,于是被迫代替她去往敵國(guó)和親蠕蚜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 在Java NIO中癣疟,Buffer用于與Channel交互潮酒。數(shù)據(jù)從Channel讀入Buffer,并從Buffer...
    d3f59bfc7013閱讀 291評(píng)論 0 1
  • Java NIO Buffer與Channel需要配合來(lái)使用。如你所知勃教,數(shù)據(jù)是從channel被讀取至buffer...
    kopshome閱讀 340評(píng)論 0 0
  • 更多 Java IO & NIO方面的文章荣回,請(qǐng)參見(jiàn)文集《Java IO & NIO》 Java IO VS NIO...
    專(zhuān)職跑龍?zhí)?/span>閱讀 1,090評(píng)論 1 5
  • Java NIO(New IO)是從Java 1.4版本開(kāi)始引入的一個(gè)新的IO API壕吹,可以替代標(biāo)準(zhǔn)的Java I...
    zhisheng_blog閱讀 1,120評(píng)論 0 7
  • 在神話的基礎(chǔ)上產(chǎn)生了宗教耳贬,宗教受到科學(xué)的抨擊猎唁。然而神話是人類(lèi)集體潛意識(shí)的展現(xiàn),如果我們只是從顯性的內(nèi)容解讀神話腐魂。就...
    津城燕窩Donna閱讀 280評(píng)論 0 0