摘要:一緩沖區(qū)介紹用于和交互。的容量,位置,上限緩沖區(qū)實質(zhì)上就是一塊內(nèi)存,用于寫入數(shù)據(jù),也供后續(xù)再次讀取數(shù)據(jù)。在每個類中,方法用于分配緩沖區(qū)。沒有這句話會報錯將此緩沖區(qū)的位置重置為先前標(biāo)記的位置。返回此緩沖區(qū)的限制。
一 Buffer(緩沖區(qū))介紹
Java NIO Buffers用于和NIO Channel交互。 我們從Channel中讀取數(shù)據(jù)到buffers里,從Buffer把數(shù)據(jù)寫入到Channels.
Buffer本質(zhì)上就是一塊內(nèi)存區(qū),可以用來寫入數(shù)據(jù),并在稍后讀取出來。這塊內(nèi)存被NIO Buffer包裹起來,對外提供一系列的讀寫方便開發(fā)的接口。
在Java NIO中使用的核心緩沖區(qū)如下(覆蓋了通過I/O發(fā)送的基本數(shù)據(jù)類型:byte, char、short, int, long, float, double ,long):
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
FloatBuffer
DoubleBuffer
LongBuffer
利用Buffer讀寫數(shù)據(jù),通常遵循四個步驟:把數(shù)據(jù)寫入buffer;
調(diào)用flip;
從Buffer中讀取數(shù)據(jù);
調(diào)用buffer.clear()或者buffer.compact()。
當(dāng)寫入數(shù)據(jù)到buffer中時,buffer會記錄已經(jīng)寫入的數(shù)據(jù)大小。當(dāng)需要讀數(shù)據(jù)時,通過 flip() 方法把buffer從寫模式調(diào)整為讀模式;在讀模式下,可以讀取所有已經(jīng)寫入的數(shù)據(jù)。
當(dāng)讀取完數(shù)據(jù)后,需要清空buffer,以滿足后續(xù)寫入操作。清空buffer有兩種方式:調(diào)用 clear() 或 compact() 方法。clear會清空整個buffer,compact則只清空已讀取的數(shù)據(jù),未被讀取的數(shù)據(jù)會被移動到buffer的開始位置,寫入位置則近跟著未讀數(shù)據(jù)之后。
Buffer的容量,位置,上限(Buffer Capacity, Position and Limit)Buffer緩沖區(qū)實質(zhì)上就是一塊內(nèi)存,用于寫入數(shù)據(jù),也供后續(xù)再次讀取數(shù)據(jù)。這塊內(nèi)存被NIO Buffer管理,并提供一系列的方法用于更簡單的操作這塊內(nèi)存。
一個Buffer有三個屬性是必須掌握的,分別是:
capacity容量
position位置
limit限制
position和limit的具體含義取決于當(dāng)前buffer的模式。capacity在兩種模式下都表示容量。
下面有張示例圖,描訴了讀寫模式下position和limit的含義:
容量(Capacity)
作為一塊內(nèi)存,buffer有一個固定的大小,叫做capacit(容量)。也就是最多只能寫入容量值得字節(jié),整形等數(shù)據(jù)。一旦buffer寫滿了就需要清空已讀數(shù)據(jù)以便下次繼續(xù)寫入新的數(shù)據(jù)。
位置(Position)
當(dāng)寫入數(shù)據(jù)到Buffer的時候需要從一個確定的位置開始,默認(rèn)初始化時這個位置position為0,一旦寫入了數(shù)據(jù)比如一個字節(jié),整形數(shù)據(jù),那么position的值就會指向數(shù)據(jù)之后的一個單元,position最大可以到capacity-1.
當(dāng)從Buffer讀取數(shù)據(jù)時,也需要從一個確定的位置開始。buffer從寫入模式變?yōu)樽x取模式時,position會歸零,每次讀取后,position向后移動。
上限(Limit)
在寫模式,limit的含義是我們所能寫入的最大數(shù)據(jù)量,它等同于buffer的容量。
一旦切換到讀模式,limit則代表我們所能讀取的最大數(shù)據(jù)量,他的值等同于寫模式下position的位置。換句話說,您可以讀取與寫入數(shù)量相同的字節(jié)數(shù)(限制設(shè)置為寫入的字節(jié)數(shù),由位置標(biāo)記)。
二 Buffer的常見方法方法 | 介紹 |
---|---|
abstract Object array() | 返回支持此緩沖區(qū)的數(shù)組 (可選操作) |
abstract int arrayOffset() | 返回該緩沖區(qū)的緩沖區(qū)的第一個元素的背襯數(shù)組中的偏移量 (可選操作) |
int capacity() | 返回此緩沖區(qū)的容量 |
Buffer clear() | 清除此緩存區(qū)。將position = 0;limit = capacity;mark = -1; |
Buffer flip() | flip()方法可以吧Buffer從寫模式切換到讀模式。調(diào)用flip方法會把position歸零,并設(shè)置limit為之前的position的值。 也就是說,現(xiàn)在position代表的是讀取位置,limit標(biāo)示的是已寫入的數(shù)據(jù)位置。 |
abstract boolean hasArray() | 告訴這個緩沖區(qū)是否由可訪問的數(shù)組支持 |
boolean hasRemaining() | return position < limit,返回是否還有未讀內(nèi)容 |
abstract boolean isDirect() | 判斷個緩沖區(qū)是否為 direct |
abstract boolean isReadOnly() | 判斷告知這個緩沖區(qū)是否是只讀的 |
int limit() | 返回此緩沖區(qū)的限制 |
Buffer position(int newPosition) | 設(shè)置這個緩沖區(qū)的位置 |
int remaining() | return limit - position; 返回limit和position之間相對位置差 |
Buffer rewind() | 把position設(shè)為0,mark設(shè)為-1,不改變limit的值 |
Buffer mark() | 將此緩沖區(qū)的標(biāo)記設(shè)置在其位置 |
分配緩沖區(qū)(Allocating a Buffer)
為了獲得緩沖區(qū)對象,我們必須首先分配一個緩沖區(qū)。在每個Buffer類中,allocate()方法用于分配緩沖區(qū)。
下面來看看ByteBuffer分配容量為28字節(jié)的例子:
ByteBuffer buf = ByteBuffer.allocate(28);
下面來看看另一個示例:CharBuffer分配空間大小為2048個字符。
CharBuffer buf = CharBuffer.allocate(2048);
寫入數(shù)據(jù)到緩沖區(qū)(Writing Data to a Buffer)
寫數(shù)據(jù)到Buffer有兩種方法:
從Channel中寫數(shù)據(jù)到Buffer
手動寫數(shù)據(jù)到Buffer,調(diào)用put方法
下面是一個實例,演示從Channel寫數(shù)據(jù)到Buffer:
int bytesRead = inChannel.read(buf); //read into buffer.
通過put寫數(shù)據(jù):
buf.put(127);
put方法有很多不同版本,對應(yīng)不同的寫數(shù)據(jù)方法。例如把數(shù)據(jù)寫到特定的位置,或者把一個字節(jié)數(shù)據(jù)寫入buffer。看考JavaDoc文檔可以查閱的更多數(shù)據(jù)。
翻轉(zhuǎn)(flip())
flip()方法可以吧Buffer從寫模式切換到讀模式。調(diào)用flip方法會把position歸零,并設(shè)置limit為之前的position的值。 也就是說,現(xiàn)在position代表的是讀取位置,limit標(biāo)示的是已寫入的數(shù)據(jù)位置。
從Buffer讀取數(shù)據(jù)(Reading Data from a Buffer)
從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也有諸多版本,對應(yīng)了不同的讀取方式。
rewind()
Buffer.rewind()方法將position置為0,這樣我們可以重復(fù)讀取buffer中的數(shù)據(jù)。limit保持不變。
clear() and compact()
一旦我們從buffer中讀取完數(shù)據(jù),需要復(fù)用buffer為下次寫數(shù)據(jù)做準(zhǔn)備。只需要調(diào)用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就會導(dǎo)致這部分?jǐn)?shù)據(jù)被“遺忘”,因為我們沒有標(biāo)記這部分?jǐn)?shù)據(jù)未讀。
針對這種情況,如果需要保留未讀數(shù)據(jù),那么可以使用compact。 因此 compact() 和 clear() 的區(qū)別就在于: 對未讀數(shù)據(jù)的處理,是保留這部分?jǐn)?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() and compareTo()
可以用eqauls和compareTo比較兩個buffer
equals():
判斷兩個buffer相對,需滿足:
類型相同
buffer中剩余字節(jié)數(shù)相同
所有剩余字節(jié)相等
從上面的三個條件可以看出,equals只比較buffer中的部分內(nèi)容,并不會去比較每一個元素。
compareTo():
compareTo也是比較buffer中的剩余元素,只不過這個方法適用于比較排序的:
四 Buffer常用方法測試這里以ByteBuffer為例子說明抽象類Buffer的實現(xiàn)類的一些常見方法的使用:
package channel; import java.nio.ByteBuffer; public class ByteBufferMethods { public static void main(String args[]){ //分配緩沖區(qū)(Allocating a Buffer) ByteBuffer buffer = ByteBuffer.allocate(33); System.out.println("-------------Test reset-------------"); //clear()方法,position將被設(shè)回0,limit被設(shè)置成 capacity的值 buffer.clear(); // 設(shè)置這個緩沖區(qū)的位置 buffer.position(5); //將此緩沖區(qū)的標(biāo)記設(shè)置在其位置。沒有buffer.mark();這句話會報錯 buffer.mark(); buffer.position(10); System.out.println("before reset: " + buffer); //將此緩沖區(qū)的位置重置為先前標(biāo)記的位置。(buffer.position(5)) buffer.reset(); System.out.println("after reset: " + buffer); System.out.println("-------------Test rewind-------------"); buffer.clear(); buffer.position(10); //返回此緩沖區(qū)的限制。 buffer.limit(15); System.out.println("before rewind: " + buffer); //把position設(shè)為0,mark設(shè)為-1,不改變limit的值 buffer.rewind(); System.out.println("before rewind: " + buffer); System.out.println("-------------Test compact-------------"); buffer.clear(); buffer.put("abcd".getBytes()); System.out.println("before compact: " + buffer); System.out.println(new String(buffer.array())); //limit = position;position = 0;mark = -1; 翻轉(zhuǎn),也就是讓flip之后的position到limit這塊區(qū)域變成之前的0到position這塊, //翻轉(zhuǎn)就是將一個處于存數(shù)據(jù)狀態(tài)的緩沖區(qū)變?yōu)橐粋€處于準(zhǔn)備取數(shù)據(jù)的狀態(tài) buffer.flip(); System.out.println("after flip: " + buffer); //get()方法:相對讀,從position位置讀取一個byte,并將position+1,為下次讀寫作準(zhǔn)備 System.out.println((char) buffer.get()); System.out.println((char) buffer.get()); System.out.println((char) buffer.get()); System.out.println("after three gets: " + buffer); System.out.println(" " + new String(buffer.array())); //把從position到limit中的內(nèi)容移到0到limit-position的區(qū)域內(nèi),position和limit的取值也分別變成limit-position、capacity。 // 如果先將positon設(shè)置到limit,再compact,那么相當(dāng)于clear() buffer.compact(); System.out.println("after compact: " + buffer); System.out.println(" " + new String(buffer.array())); System.out.println("-------------Test get-------------"); buffer = ByteBuffer.allocate(32); buffer.put((byte) "a").put((byte) "b").put((byte) "c").put((byte) "d") .put((byte) "e").put((byte) "f"); System.out.println("before flip(): " + buffer); // 轉(zhuǎn)換為讀取模式 buffer.flip(); System.out.println("before get(): " + buffer); System.out.println((char) buffer.get()); System.out.println("after get(): " + buffer); // get(index)不影響position的值 System.out.println((char) buffer.get(2)); System.out.println("after get(index): " + buffer); byte[] dst = new byte[10]; buffer.get(dst, 0, 2); System.out.println("after get(dst, 0, 2): " + buffer); System.out.println(" dst:" + new String(dst)); System.out.println("buffer now is: " + buffer); System.out.println(" " + new String(buffer.array())); System.out.println("-------------Test put-------------"); ByteBuffer bb = ByteBuffer.allocate(32); System.out.println("before put(byte): " + bb); System.out.println("after put(byte): " + bb.put((byte) "z")); System.out.println(" " + bb.put(2, (byte) "c")); // put(2,(byte) "c")不改變position的位置 System.out.println("after put(2,(byte) "c"): " + bb); System.out.println(" " + new String(bb.array())); // 這里的buffer是 abcdef[pos=3 lim=6 cap=32] bb.put(buffer); System.out.println("after put(buffer): " + bb); System.out.println(" " + new String(bb.array())); } }參考:
官方JDK相關(guān)文檔
谷歌搜索排名第一的Java NIO教程
《Java程序員修煉之道》
ByteBuffer常用方法詳解
Java NIO 易百教程
歡迎關(guān)注我的微信公眾號:"Java面試通關(guān)手冊"(一個有溫度的微信公眾號,期待與你共同進(jìn)步~~~堅持原創(chuàng),分享美文,分享各種Java學(xué)習(xí)資源):
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69395.html
摘要:從通道進(jìn)行數(shù)據(jù)寫入創(chuàng)建一個緩沖區(qū),填充數(shù)據(jù),并要求通道寫入數(shù)據(jù)。三之通道主要內(nèi)容通道介紹通常來說中的所有都是從通道開始的。從中選擇選擇器維護(hù)注冊過的通道的集合,并且這種注冊關(guān)系都被封裝在當(dāng)中停止選擇的方法方法和方法。 由于內(nèi)容比較多,我下面放的一部分是我更新在我的微信公眾號上的鏈接,微信排版比較好看,更加利于閱讀。每一篇文章下面我都把文章的主要內(nèi)容給列出來了,便于大家學(xué)習(xí)與回顧。 Ja...
摘要:通道可以異步讀寫。使用的方法讀取數(shù)據(jù)創(chuàng)建一個讀數(shù)據(jù)緩沖區(qū)對象從通道中讀取數(shù)據(jù)使用的方法寫入數(shù)據(jù)創(chuàng)建一個寫數(shù)據(jù)緩沖區(qū)對象寫入數(shù)據(jù)關(guān)閉完成使用后,您必須關(guān)閉它。五提供了一種被稱為的新功能,也稱為本地矢量。功能是通道提供的并不是。 歷史回顧: Java NIO 概覽 Java NIO 之 Buffer(緩沖區(qū)) 其他高贊文章: 面試中關(guān)于Redis的問題看這篇就夠了 一文輕松搞懂redis集...
摘要:上篇說了最基礎(chǔ)的五種模型,相信大家對相關(guān)的概念應(yīng)該有了一定的了解,這篇文章主要講講基于多路復(fù)用的。 上篇說了最基礎(chǔ)的五種IO模型,相信大家對IO相關(guān)的概念應(yīng)該有了一定的了解,這篇文章主要講講基于多路復(fù)用IO的Java NIO。 背景 Java誕生至今,有好多種IO模型,從最早的Java IO到后來的Java NIO以及最新的Java AIO,每種IO模型都有它自己的特點,詳情請看我的上...
摘要:學(xué)習(xí)和掌握技術(shù)已經(jīng)不是一個攻城獅的加分技能,而是一個必備技能。是雙向的,不僅可以讀取數(shù)據(jù)還能保存數(shù)據(jù),程序不能直接讀寫通道,只與緩沖區(qū)交互為了讓大家不被高并發(fā)與大量連接處理問題所困擾,動力節(jié)點推出了高效處理模型應(yīng)用教程。 大家肯定了解Java IO, 但是對于NIO一般是陌生的,而現(xiàn)在使用到NIO的場景越來越多,很多技術(shù)框...
摘要:線程之間的切換對于操作系統(tǒng)來說是昂貴的。因此,單線程可以監(jiān)視多個通道中的數(shù)據(jù)。當(dāng)方法返回后,線程可以處理這些事件。 一 NIO簡介 Java NIO 是 java 1.4 之后新出的一套IO接口,這里的的新是相對于原有標(biāo)準(zhǔn)的Java IO和Java Networking接口。NIO提供了一種完全不同的操作方式。 NIO中的N可以理解為Non-blocking,不單純是New。 它支持面...
閱讀 2020·2021-10-09 09:41
閱讀 1596·2021-09-28 09:36
閱讀 1100·2021-09-26 09:55
閱讀 1285·2021-09-10 11:17
閱讀 1141·2021-09-02 09:56
閱讀 2755·2019-08-30 12:58
閱讀 2927·2019-08-29 13:03
閱讀 1847·2019-08-26 13:40