參考教程http://ifeve.com/java-nio-all/
1.Channel
Java NIO的通道類似流,但又有些不同:
- 既可以從通道中讀取數(shù)據(jù),又可以寫數(shù)據(jù)到通道。但流的讀寫通常是單向的。
- 通道可以異步地讀寫。
- 通道中的數(shù)據(jù)總是要先讀到一個(gè)Buffer,或者總是要從一個(gè)Buffer中寫入。
正如上面所說(shuō),從通道讀取數(shù)據(jù)到緩沖區(qū),從緩沖區(qū)寫入數(shù)據(jù)到通道。如下圖所示:

Channel的實(shí)現(xiàn)
這些是Java NIO中最重要的通道的實(shí)現(xiàn):
- FileChannel 從文件中讀寫數(shù)據(jù)。
- DatagramChannel 能通過(guò)UDP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。
- SocketChannel 能通過(guò)TCP讀寫網(wǎng)絡(luò)中的數(shù)據(jù)。
- ServerSocketChannel可以監(jiān)聽(tīng)新進(jìn)來(lái)的TCP連接,像Web服務(wù)器那樣。對(duì)每一個(gè)新進(jìn)來(lái)的連接都會(huì)創(chuàng)建一個(gè)SocketChannel。
2.Buffer
Java NIO中的Buffer用于和NIO通道進(jìn)行交互。如你所知,數(shù)據(jù)是從通道讀入緩沖區(qū),從緩沖區(qū)寫入到通道中的。
緩沖區(qū)本質(zhì)上是一塊可以寫入數(shù)據(jù),然后可以從中讀取數(shù)據(jù)的內(nèi)存。這塊內(nèi)存被包裝成NIO Buffer對(duì)象,并提供了一組方法,用來(lái)方便的訪問(wèn)該塊內(nèi)存。
Buffer的capacity,position和limit
緩沖區(qū)本質(zhì)上是一塊可以寫入數(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處在讀模式還是寫模式。不管Buffer處在什么模式,capacity的含義總是一樣的。
capacity
作為一個(gè)內(nèi)存塊,Buffer有一個(gè)固定的大小值,也叫“capacity”.你只能往里寫capacity個(gè)byte、long,char等類型。一旦Buffer滿了,需要將其清空(通過(guò)讀數(shù)據(jù)或者清除數(shù)據(jù))才能繼續(xù)寫數(shù)據(jù)往里寫數(shù)據(jù)。
position
當(dāng)你寫數(shù)據(jù)到Buffer中時(shí),position表示當(dāng)前的位置。初始的position值為0.當(dāng)一個(gè)byte、long等數(shù)據(jù)寫到Buffer后, position會(huì)向前移動(dòng)到下一個(gè)可插入數(shù)據(jù)的Buffer單元。position最大可為capacity(存疑).
當(dāng)讀取數(shù)據(jù)時(shí),也是從某個(gè)特定位置讀。當(dāng)將Buffer從寫模式切換到讀模式,position會(huì)被重置為0. 當(dāng)從Buffer的position處讀取數(shù)據(jù)時(shí),position向前移動(dòng)到下一個(gè)可讀的位置。
limit
在寫模式下,Buffer的limit表示你最多能往Buffer里寫多少數(shù)據(jù)。 寫模式下,limit等于Buffer的capacity。
當(dāng)切換Buffer到讀模式時(shí), limit表示你最多能讀到多少數(shù)據(jù)。因此,當(dāng)切換Buffer到讀模式時(shí),limit會(huì)被設(shè)置成寫模式下的position值。換句話說(shuō),你能讀到之前寫入的所有數(shù)據(jù)(limit被設(shè)置成已寫數(shù)據(jù)的數(shù)量,這個(gè)值在寫模式下就是position)
Java NIO 有以下Buffer類型
ByteBuffer
MappedByteBuffer(比較特殊,單獨(dú)講它)
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
如你所見(jiàn),這些Buffer類型代表了不同的數(shù)據(jù)類型。換句話說(shuō),就是可以通過(guò)char,short,int,long,float 或 double類型來(lái)操作緩沖區(qū)中的字節(jié)。
讀寫方法查看http://ifeve.com/buffers/
注意flip()方法
flip方法將Buffer從寫模式切換到讀模式。調(diào)用flip()方法會(huì)將position設(shè)回0,并將limit設(shè)置成之前position的值。
換句話說(shuō),position現(xiàn)在用于標(biāo)記讀的位置,limit表示之前寫進(jìn)了多少個(gè)byte、char等 —— 現(xiàn)在能讀取多少個(gè)byte、char等。
rewind()方法:Buffer.rewind()將position設(shè)回0
clear()與compact()方法:
compact()方法將所有未讀的數(shù)據(jù)拷貝到Buffer起始處。然后將position設(shè)到最后一個(gè)未讀元素正后面。limit屬性依然像clear()方法一樣,設(shè)置成capacity?,F(xiàn)在Buffer準(zhǔn)備好寫數(shù)據(jù)了,但是不會(huì)覆蓋未讀的數(shù)據(jù)。
mark()與reset()方法
equals()與compareTo()方法
3. Scatter/Gather
原文地址:http://tutorials.jenkov.com/java-nio/scatter-gather.html
Java NIO開(kāi)始支持scatter/gather,scatter/gather用于描述從Channel(譯者注:Channel在中文經(jīng)常翻譯為通道)中讀取或者寫入到Channel的操作。
分散(scatter)從Channel中讀取是指在讀操作時(shí)將讀取的數(shù)據(jù)寫入多個(gè)buffer中。因此,Channel將從Channel中讀取的數(shù)據(jù)“分散(scatter)”到多個(gè)Buffer中。
聚集(gather)寫入Channel是指在寫操作時(shí)將多個(gè)buffer的數(shù)據(jù)寫入同一個(gè)Channel,因此,Channel 將多個(gè)Buffer中的數(shù)據(jù)“聚集(gather)”后發(fā)送到Channel。
scatter / gather經(jīng)常用于需要將傳輸?shù)臄?shù)據(jù)分開(kāi)處理的場(chǎng)合,例如傳輸一個(gè)由消息頭和消息體組成的消息,你可能會(huì)將消息體和消息頭分散到不同的buffer中,這樣你可以方便的處理消息頭和消息體。
Scattering Reads
Scattering Reads是指數(shù)據(jù)從一個(gè)channel讀取到多個(gè)buffer中。
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(bufferArray);
注意buffer首先被插入到數(shù)組,然后再將數(shù)組作為channel.read() 的輸入?yún)?shù)。read()方法按照buffer在數(shù)組中的順序?qū)腸hannel中讀取的數(shù)據(jù)寫入到buffer,當(dāng)一個(gè)buffer被寫滿后,channel緊接著向另一個(gè)buffer中寫。
Scattering Reads在移動(dòng)下一個(gè)buffer前,必須填滿當(dāng)前的buffer,這也意味著它不適用于動(dòng)態(tài)消息(譯者注:消息大小不固定)。換句話說(shuō),如果存在消息頭和消息體,消息頭必須完成填充(例如 128byte),Scattering Reads才能正常工作。
Gathering Writes
Gathering Writes是指數(shù)據(jù)從多個(gè)buffer寫入到同一個(gè)channel。
ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body = ByteBuffer.allocate(1024);
//write data into buffers
ByteBuffer[] bufferArray = { header, body };
channel.write(bufferArray);
buffers數(shù)組是write()方法的入?yún)?,write()方法會(huì)按照buffer在數(shù)組中的順序,將數(shù)據(jù)寫入到channel,注意只有position和limit之間的數(shù)據(jù)才會(huì)被寫入。因此,如果一個(gè)buffer的容量為128byte,但是僅僅包含58byte的數(shù)據(jù),那么這58byte的數(shù)據(jù)將被寫入到channel中。因此與Scattering Reads相反,Gathering Writes能較好的處理動(dòng)態(tài)消息。
待續(xù)。。。。。。