分散/聚集 I/O 是使用多個而不是單個緩沖區來儲存資料的讀寫方法。
一個分散的讀取就像一個正常通道讀取,隻不過它是将資料讀到一個緩沖區數組中而不是讀到單個緩沖區中。同樣地,一個聚集寫入是向緩沖區數組而不是向單個緩沖區寫入資料。
分散/聚集 I/O 對于将資料流劃分為單獨的部分很有用,這有助于實作複雜的資料格式。
通道可以有選擇地實作兩個新的接口: ScatteringByteChannel 和 GatheringByteChannel。一個 ScatteringByteChannel 是一個具有兩個附加讀方法的通道:
<code>long</code> <code>read( ByteBuffer[] dsts );</code>
<code>long</code> <code>read( ByteBuffer[] dsts, </code><code>int</code> <code>offset, </code><code>int</code> <code>length );</code>
這些 long read()方法很像标準的 read 方法,隻不過它們不是取單個緩沖區而是取一個緩沖區數組。
在分散讀取中,通道依次填充每個緩沖區。填滿一個緩沖區後,它就開始填充下一個。在某種意義上,緩沖區數組就像一個大緩沖區。
分散/聚集 I/O 對于将資料劃分為幾個部分很有用。例如,您可能在編寫一個使用消息對象的網絡應用程式,每一個消息被劃分為固定長度的頭部和固定長度的正文。您可以建立一個剛好可以容納頭部的緩沖區和另一個剛好可以容難正文的緩沖區。當您将它們放入一個數組中并使用分散讀取來向它們讀入消息時,頭部和正文将整齊地劃分到這兩個緩沖區中。
我們從緩沖區所得到的友善性對于緩沖區數組同樣有效。因為每一個緩沖區都跟蹤自己還可以接受多少資料,是以分散讀取會自動找到有空間接受資料的第一個緩沖區。在這個緩沖區填滿後,它就會移動到下一個緩沖區。
聚集寫入類似于分散讀取,隻不過是用來寫入。它也有接受緩沖區數組的方法:
<code>long</code> <code>write( ByteBuffer[] srcs );</code>
<code>long</code> <code>write( ByteBuffer[] srcs, </code><code>int</code> <code>offset, </code><code>int</code> <code>length );</code>
聚集寫對于把一組單獨的緩沖區中組成單個資料流很有用。為了與上面的消息例子保持一緻,您可以使用聚集寫入來自動将網絡消息的各個部分組裝為單個資料流,以便跨越網絡傳輸消息。
從例子程式UseScatterGather.java 中可以看到分散讀取和聚集寫入的實際應用。
<code>// UseScatterGather</code>
<code>import</code> <code>java.io.*;</code>
<code>import</code> <code>java.net.*;</code>
<code>import</code> <code>java.nio.*;</code>
<code>import</code> <code>java.nio.channels.*;</code>
<code>public</code> <code>class</code> <code>UseScatterGather</code>
<code>{</code>
<code> </code><code>static</code> <code>private</code> <code>final</code> <code>int</code> <code>firstHeaderLength = </code><code>2</code><code>;</code>
<code> </code><code>static</code> <code>private</code> <code>final</code> <code>int</code> <code>secondHeaderLength = </code><code>4</code><code>;</code>
<code> </code><code>static</code> <code>private</code> <code>final</code> <code>int</code> <code>bodyLength = </code><code>6</code><code>;</code>
<code> </code><code>static</code> <code>public</code> <code>void</code> <code>main( String args[] ) </code><code>throws</code> <code>Exception {</code>
<code> </code><code>if</code> <code>(args.length!=</code><code>1</code><code>) {</code>
<code> </code><code>System.err.println( </code><code>"Usage: java UseScatterGather port"</code> <code>);</code>
<code> </code><code>System.exit( </code><code>1</code> <code>);</code>
<code> </code><code>}</code>
<code> </code><code>int</code> <code>port = Integer.parseInt( args[</code><code>0</code><code>] );</code>
<code> </code><code>ServerSocketChannel ssc = ServerSocketChannel.open();</code>
<code> </code><code>InetSocketAddress address = </code><code>new</code> <code>InetSocketAddress( port );</code>
<code> </code><code>ssc.socket().bind( address );</code>
<code> </code><code>int</code> <code>messageLength =</code>
<code> </code><code>firstHeaderLength + secondHeaderLength + bodyLength;</code>
<code> </code><code>ByteBuffer buffers[] = </code><code>new</code> <code>ByteBuffer[</code><code>3</code><code>];</code>
<code> </code><code>buffers[</code><code>0</code><code>] = ByteBuffer.allocate( firstHeaderLength );</code>
<code> </code><code>buffers[</code><code>1</code><code>] = ByteBuffer.allocate( secondHeaderLength );</code>
<code> </code><code>buffers[</code><code>2</code><code>] = ByteBuffer.allocate( bodyLength );</code>
<code> </code><code>SocketChannel sc = ssc.accept();</code>
<code> </code><code>while</code> <code>(</code><code>true</code><code>) {</code>
<code> </code><code>// Scatter-read into buffers</code>
<code> </code><code>int</code> <code>bytesRead = </code><code>0</code><code>;</code>
<code> </code><code>while</code> <code>(bytesRead < messageLength) {</code>
<code> </code><code>long</code> <code>r = sc.read( buffers );</code>
<code> </code><code>bytesRead += r;</code>
<code> </code><code>System.out.println( </code><code>"r "</code><code>+r );</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i<buffers.length; ++i) {</code>
<code> </code><code>ByteBuffer bb = buffers[i];</code>
<code> </code><code>System.out.println( </code><code>"b "</code><code>+i+</code><code>" "</code><code>+bb.position()+</code><code>" "</code><code>+bb.limit() );</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>// Process message here</code>
<code> </code><code>// Flip buffers</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i=</code><code>0</code><code>; i<buffers.length; ++i) {</code>
<code> </code><code>ByteBuffer bb = buffers[i];</code>
<code> </code><code>bb.flip();</code>
<code> </code><code>// Scatter-write back out</code>
<code> </code><code>long</code> <code>bytesWritten = </code><code>0</code><code>;</code>
<code> </code><code>while</code> <code>(bytesWritten<messageLength) {</code>
<code> </code><code>long</code> <code>r = sc.write( buffers );</code>
<code> </code><code>bytesWritten += r;</code>
<code> </code><code>// Clear buffers</code>
<code> </code><code>bb.clear();</code>
<code> </code><code>System.out.println( bytesRead+</code><code>" "</code><code>+bytesWritten+</code><code>" "</code><code>+messageLength );</code>
<code> </code><code>}</code>
<code>}</code>
版權聲明:原創作品,如需轉載,請注明出處。否則将追究法律責任
本文轉自 夢朝思夕 51CTO部落格,原文連結:http://blog.51cto.com/qiangmzsx/1410776