【永恒的瞬間】
          ?Give me hapy ?

          NIO API 主要集中在 java.nio 和它的 subpackages 中:

          ?

          java.nio

          定義了 Buffer 及其數(shù)據(jù)類(lèi)型相關(guān)的子類(lèi)。其中被 java.nio.channels 中的類(lèi)用來(lái)進(jìn)行 IO 操作的 ByteBuffer 的作用非常重要。

          ?

          java.nio.channels

          定義了一系列處理 IO Channel 接口以及這些接口在文件系統(tǒng)和網(wǎng)絡(luò)通訊上的實(shí)現(xiàn)。通過(guò) Selector 這個(gè)類(lèi),還提供了進(jìn)行非阻塞 IO 操作的辦法。這個(gè)包可以說(shuō)是 NIO API 的核心。

          ?

          java.nio.channels.spi

          定義了可用來(lái)實(shí)現(xiàn) channel selector API 的抽象類(lèi)。

          ?

          java.nio.charset

          ?????? 定義了處理字符編碼和解碼的類(lèi)。

          ?

          java.nio.charset.spi

          ?????? 定義了可用來(lái)實(shí)現(xiàn) charset API 的抽象類(lèi)。

          ?

          java.nio.channels.spi java.nio.charset.spi 這兩個(gè)包主要被用來(lái)對(duì)現(xiàn)有 NIO API 進(jìn)行擴(kuò)展,在實(shí)際的使用中,我們一般只和另外的 3 個(gè)包打交道。下面將對(duì)這 3 個(gè)包一一介紹。

          ?

          Package java.nio

          這個(gè)包主要定義了 Buffer 及其子類(lèi)。 Buffer 定義了一個(gè)線(xiàn)性存放 primitive type 數(shù)據(jù)的容器接口。對(duì)于除 boolean 以外的其他 primitive type ,都有一個(gè)相應(yīng)的 Buffer 子類(lèi), ByteBuffer 是其中最重要的一個(gè)子類(lèi)。

          ?

          下面這張 UML 類(lèi)圖描述了 java.nio 中的類(lèi)的關(guān)系:



          ?

          Buffer

          定義了一個(gè)可以線(xiàn)性存放 primitive type 數(shù)據(jù)的容器接口。 Buffer 主要包含了與類(lèi)型( byte, char… )無(wú)關(guān)的功能。值得注意的是 Buffer 及其子類(lèi)都不是線(xiàn)程安全的。

          ?

          每個(gè) Buffer 都有以下的屬性:

          ?

          capacity

          這個(gè) Buffer 最多能放多少數(shù)據(jù)。 capacity 一般在 buffer 被創(chuàng)建的時(shí)候指定。

          limit

          Buffer 上進(jìn)行的讀寫(xiě)操作都不能越過(guò)這個(gè)下標(biāo)。當(dāng)寫(xiě)數(shù)據(jù)到 buffer 中時(shí), limit 一般和 capacity 相等,當(dāng)讀數(shù)據(jù)時(shí), limit 代表 buffer 中有效數(shù)據(jù)的長(zhǎng)度。

          position

          / 寫(xiě)操作的當(dāng)前下標(biāo)。當(dāng)使用 buffer 的相對(duì)位置進(jìn)行讀 / 寫(xiě)操作時(shí),讀 / 寫(xiě)會(huì)從這個(gè)下標(biāo)進(jìn)行,并在操作完成后, buffer 會(huì)更新下標(biāo)的值。

          mark

          一個(gè)臨時(shí)存放的位置下標(biāo)。調(diào)用 mark() 會(huì)將 mark 設(shè)為當(dāng)前的 position 的值,以后調(diào)用 reset() 會(huì)將 position 屬性設(shè)置為 mark 的值。 mark 的值總是小于等于 position 的值,如果將 position 的值設(shè)的比 mark 小,當(dāng)前的 mark 值會(huì)被拋棄掉。

          ?

          這些屬性總是滿(mǎn)足以下條件:

          0 <= mark <= position <= limit <= capacity

          ?

          limit position 的值除了通過(guò) limit() position() 函數(shù)來(lái)設(shè)置,也可以通過(guò)下面這些函數(shù)來(lái)改變:

          ?

          Buffer clear()

          position 設(shè)為 0 ,把 limit 設(shè)為 capacity ,一般在把數(shù)據(jù)寫(xiě)入 Buffer 前調(diào)用。

          Buffer flip()

          limit 設(shè)為當(dāng)前 position ,把 position 設(shè)為 0 ,一般在從 Buffer 讀出數(shù)據(jù)前調(diào)用。

          Buffer rewind()

          position 設(shè)為 0 , limit 不變,一般在把數(shù)據(jù)重寫(xiě)入 Buffer 前調(diào)用。

          ?

          Buffer 對(duì)象有可能是只讀的,這時(shí),任何對(duì)該對(duì)象的寫(xiě)操作都會(huì)觸發(fā)一個(gè) ReadOnlyBufferException 。 isReadOnly() 方法可以用來(lái)判斷一個(gè) Buffer 是否只讀。

          ?

          ByteBuffer

          Buffer 的子類(lèi)中, ByteBuffer 是一個(gè)地位較為特殊的類(lèi),因?yàn)樵?/span> java.io.channels 中定義的各種 channel IO 操作基本上都是圍繞 ByteBuffer 展開(kāi)的。

          ?

          ByteBuffer 定義了 4 個(gè) static 方法來(lái)做創(chuàng)建工作:

          ?

          ByteBuffer allocate(int capacity)

          創(chuàng)建一個(gè)指定 capacity ByteBuffer 。

          ByteBuffer allocateDirect(int capacity)

          創(chuàng)建一個(gè) direct ByteBuffer ,這樣的 ByteBuffer 在參與 IO 操作時(shí)性能會(huì)更好(很有可能是在底層的實(shí)現(xiàn)使用了 DMA 技術(shù)),相應(yīng)的,創(chuàng)建和回收 direct ByteBuffer 的代價(jià)也會(huì)高一些。 isDirect() 方法可以檢查一個(gè) buffer 是否是 direct 的。

          ByteBuffer wrap(byte [] array)

          ByteBuffer wrap(byte [] array, int offset, int length)

          把一個(gè) byte 數(shù)組或 byte 數(shù)組的一部分包裝成 ByteBuffer

          ?

          ByteBuffer 定義了一系列 get put 操作來(lái)從中讀寫(xiě) byte 數(shù)據(jù),如下面幾個(gè):

          ?

          byte get()

          ByteBuffer get(byte [] dst)

          byte get(int index)

          ?

          ByteBuffer put(byte b)

          ByteBuffer put(byte [] src)

          ByteBuffer put(int index, byte b)

          ?

          這些操作可分為絕對(duì)定位和相對(duì)定為兩種,相對(duì)定位的讀寫(xiě)操作依靠 position 來(lái)定位 Buffer 中的位置,并在操作完成后會(huì)更新 position 的值。

          在其它類(lèi)型的 buffer 中,也定義了相同的函數(shù)來(lái)讀寫(xiě)數(shù)據(jù),唯一不同的就是一些參數(shù)和返回值的類(lèi)型。

          ?

          除了讀寫(xiě) byte 類(lèi)型數(shù)據(jù)的函數(shù), ByteBuffer 的一個(gè)特別之處是它還定義了讀寫(xiě)其它 primitive 數(shù)據(jù)的方法,如:

          ?

          int getInt()

          ?????? ByteBuffer 中讀出一個(gè) int 值。

          ByteBuffer putInt(int value)

          ?????? 寫(xiě)入一個(gè) int 值到 ByteBuffer 中。

          ?

          讀寫(xiě)其它類(lèi)型的數(shù)據(jù)牽涉到字節(jié)序問(wèn)題, ByteBuffer 會(huì)按其字節(jié)序(大字節(jié)序或小字節(jié)序)寫(xiě)入或讀出一個(gè)其它類(lèi)型的數(shù)據(jù)( int,long… )。字節(jié)序可以用 order 方法來(lái)取得和設(shè)置:

          ?

          ByteOrder order()

          ?????? 返回 ByteBuffer 的字節(jié)序。

          ByteBuffer order(ByteOrder bo)

          ?????? 設(shè)置 ByteBuffer 的字節(jié)序。

          ?

          ByteBuffer 另一個(gè)特別的地方是可以在它的基礎(chǔ)上得到其它類(lèi)型的 buffer 。如:

          ?

          CharBuffer asCharBuffer()

          為當(dāng)前的 ByteBuffer 創(chuàng)建一個(gè) CharBuffer 的視圖。在該視圖 buffer 中的讀寫(xiě)操作會(huì)按照 ByteBuffer 的字節(jié)序作用到 ByteBuffer 中的數(shù)據(jù)上。

          ?

          用這類(lèi)方法創(chuàng)建出來(lái)的 buffer 會(huì)從 ByteBuffer position 位置開(kāi)始到 limit 位置結(jié)束,可以看作是這段數(shù)據(jù)的視圖。視圖 buffer readOnly 屬性和 direct 屬性與 ByteBuffer 的一致,而且也只有通過(guò)這種方法,才可以得到其他數(shù)據(jù)類(lèi)型的 direct buffer 。

          ?

          ByteOrder

          用來(lái)表示 ByteBuffer 字節(jié)序的類(lèi),可將其看成 java 中的 enum 類(lèi)型。主要定義了下面幾個(gè) static 方法和屬性:

          ?

          ByteOrder BIG_ENDIAN

          ?????? 代表大字節(jié)序的 ByteOrder 。

          ByteOrder LITTLE_ENDIAN

          ?????? 代表小字節(jié)序的 ByteOrder 。

          ByteOrder nativeOrder()

          ?????? 返回當(dāng)前硬件平臺(tái)的字節(jié)序。

          ?

          MappedByteBuffer

          ByteBuffer 的子類(lèi),是文件內(nèi)容在內(nèi)存中的映射。這個(gè)類(lèi)的實(shí)例需要通過(guò) FileChannel map() 方法來(lái)創(chuàng)建。

          ?

          ?

          接下來(lái)看看一個(gè)使用 ByteBuffer 的例子,這個(gè)例子從標(biāo)準(zhǔn)輸入不停地讀入字符,當(dāng)讀滿(mǎn)一行后,將收集的字符寫(xiě)到標(biāo)準(zhǔn)輸出:

          ??? public static void main(String [] args)

          ?????? throws IOException

          ??? {

          ?????? // 創(chuàng)建一個(gè) capacity 256 ByteBuffer

          ?????? ByteBuffer buf = ByteBuffer.allocate(256);

          ?????? while ( true ) {

          ?????????? // 從標(biāo)準(zhǔn)輸入流讀入一個(gè)字符

          ?????????? int c = System.in.read();

          ?????????? // 當(dāng)讀到輸入流結(jié)束時(shí),退出循環(huán)

          ?????????? if (c == -1)

          ????????????? break ;

          ??????????

          ?????????? // 把讀入的字符寫(xiě)入 ByteBuffer

          ?????????? buf.put(( byte ) c);

          ?????????? // 當(dāng)讀完一行時(shí),輸出收集的字符

          ?????????? if (c == '\n' ) {

          ????????????? // 調(diào)用 flip() 使 limit 變?yōu)楫?dāng)前的 position 的值 ,position 變?yōu)?/span> 0,

          ????????????? // 為接下來(lái)從 ByteBuffer 讀取做準(zhǔn)備

          ????????????? buf.flip();

          ????????????? // 構(gòu)建一個(gè) byte 數(shù)組

          ????????????? byte [] content = new byte [buf.limit()];

          ????????????? // ByteBuffer 中讀取數(shù)據(jù)到 byte 數(shù)組中

          ????????????? buf.get(content);

          ?????????? ??? // byte 數(shù)組的內(nèi)容寫(xiě)到標(biāo)準(zhǔn)輸出

          ????????????? System.out.print( new String(content));

          ????????????? // 調(diào)用 clear() 使 position 變?yōu)?/span> 0,limit 變?yōu)?/span> capacity 的值,

          ????????????? // 為接下來(lái)寫(xiě)入數(shù)據(jù)到 ByteBuffer 中做準(zhǔn)備

          ????????????? buf.clear();

          ?????????? }

          ?????? }

          ??? }

          ?

          ?

          Package java.nio.channels

          這個(gè)包定義了 Channel 的概念, Channel 表現(xiàn)了一個(gè)可以進(jìn)行 IO 操作的通道(比如,通過(guò) FileChannel ,我們可以對(duì)文件進(jìn)行讀寫(xiě)操作)。 java.nio.channels 包含了文件系統(tǒng)和網(wǎng)絡(luò)通訊相關(guān)的 channel 類(lèi)。這個(gè)包通過(guò) Selector SelectableChannel 這兩個(gè)類(lèi),還定義了一個(gè)進(jìn)行非阻塞( non-blocking IO 操作的 API ,這對(duì)需要高性能 IO 的應(yīng)用非常重要。

          ?

          下面這張 UML 類(lèi)圖描述了 java.nio.channels interface 的關(guān)系:



          ?

          Channel

          Channel 表現(xiàn)了一個(gè)可以進(jìn)行 IO 操作的通道,該 interface 定義了以下方法:

          ?

          boolean isOpen()

          ?????? Channel 是否是打開(kāi)的。

          void close()

          ?????? 關(guān)閉這個(gè) Channel ,相關(guān)的資源會(huì)被釋放。

          ?

          ReadableByteChannel

          定義了一個(gè)可從中讀取 byte 數(shù)據(jù)的 channel interface

          ?

          int read(ByteBuffer dst)

          channel 中讀取 byte 數(shù)據(jù)并寫(xiě)到 ByteBuffer 中。返回讀取的 byte 數(shù)。

          ?

          WritableByteChannel

          定義了一個(gè)可向其寫(xiě) byte 數(shù)據(jù)的 channel interface 。

          ?

          int write(ByteBuffer src)

          ?????? ByteBuffer 中讀取 byte 數(shù)據(jù)并寫(xiě)到 channel 中。返回寫(xiě)出的 byte 數(shù)。

          ?

          ByteChannel

          ByteChannel 并沒(méi)有定義新的方法,它的作用只是把 ReadableByteChannel WritableByteChannel 合并在一起。

          ?

          ScatteringByteChannel

          繼承了 ReadableByteChannel 并提供了同時(shí)往幾個(gè) ByteBuffer 中寫(xiě)數(shù)據(jù)的能力。

          ?

          GatheringByteChannel

          繼承了 WritableByteChannel 并提供了同時(shí)從幾個(gè) ByteBuffer 中讀數(shù)據(jù)的能力。

          ?

          InterruptibleChannel

          用來(lái)表現(xiàn)一個(gè)可以被異步關(guān)閉的 Channel 。這表現(xiàn)在兩方面:

          1.??? 當(dāng)一個(gè) InterruptibleChannel close() 方法被調(diào)用時(shí),其它 block 在這個(gè) InterruptibleChannel IO 操作上的線(xiàn)程會(huì)接收到一個(gè) AsynchronousCloseException

          2.??? 當(dāng)一個(gè)線(xiàn)程 block InterruptibleChannel IO 操作上時(shí),另一個(gè)線(xiàn)程調(diào)用該線(xiàn)程的 interrupt() 方法會(huì)導(dǎo)致 channel 被關(guān)閉,該線(xiàn)程收到一個(gè) ClosedByInterruptException ,同時(shí)線(xiàn)程的 interrupt 狀態(tài)會(huì)被設(shè)置。

          ?

          ?

          接下來(lái)的這張 UML 類(lèi)圖描述了 java.nio.channels 中類(lèi)的關(guān)系:



          ?

          非阻塞 IO

          非阻塞 IO 的支持可以算是 NIO API 中最重要的功能,非阻塞 IO 允許應(yīng)用程序同時(shí)監(jiān)控多個(gè) channel 以提高性能,這一功能是通過(guò) Selector , SelectableChannel SelectionKey 3 個(gè)類(lèi)來(lái)實(shí)現(xiàn)的。

          ?

          SelectableChannel 代表了可以支持非阻塞 IO 操作的 channel ,可以將其注冊(cè)在 Selector 上,這種注冊(cè)的關(guān)系由 SelectionKey 這個(gè)類(lèi)來(lái)表現(xiàn)(見(jiàn) UML 圖)。 Selector 這個(gè)類(lèi)通過(guò) select() 函數(shù),給應(yīng)用程序提供了一個(gè)可以同時(shí)監(jiān)控多個(gè) IO channel 的方法:

          ?

          應(yīng)用程序通過(guò)調(diào)用 select() 函數(shù),讓 Selector 監(jiān)控注冊(cè)在其上的多個(gè) SelectableChannel ,當(dāng)有 channel IO 操作可以進(jìn)行時(shí), select() 方法就會(huì)返回以讓?xiě)?yīng)用程序檢查 channel 的狀態(tài),并作相應(yīng)的處理。

          ?

          下面是 JDK 1.4 中非阻塞 IO 的一個(gè)例子,這段 code 使用了非阻塞 IO 實(shí)現(xiàn)了一個(gè) time server

          ??? private static void acceptConnections( int port) throws Exception {

          ?????? // 打開(kāi)一個(gè) Selector

          ?????? Selector acceptSelector =

          ?????????? SelectorProvider.provider().openSelector();

          ?

          ?????? // 創(chuàng)建一個(gè) ServerSocketChannel ,這是一個(gè) SelectableChannel 的子類(lèi)

          ?????? ServerSocketChannel ssc = ServerSocketChannel.open();

          ?????? // 將其設(shè)為 non-blocking 狀態(tài),這樣才能進(jìn)行非阻塞 IO 操作

          ?????? ssc.configureBlocking( false );

          ?

          ?????? // ServerSocketChannel 對(duì)應(yīng)的 socket 綁定 IP 和端口

          ?????? InetAddress lh = InetAddress.getLocalHost();

          ?????? InetSocketAddress isa = new InetSocketAddress(lh, port);

          ?????? ssc.socket().bind(isa);

          ?

          ?????? // ServerSocketChannel 注冊(cè)到 Selector 上,返回對(duì)應(yīng)的 SelectionKey

          ?????? SelectionKey acceptKey =

          ?????????? ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);

          ?

          ?????? int keysAdded = 0;

          ?

          ?????? // select() 函數(shù)來(lái)監(jiān)控注冊(cè)在 Selector 上的 SelectableChannel

          ?????? // 返回值代表了有多少 channel 可以進(jìn)行 IO 操作 (ready for IO)

          ?????? while ((keysAdded = acceptSelector.select()) > 0) {

          ?????????? // selectedKeys() 返回一個(gè) SelectionKey 的集合,

          ?????????? // 其中每個(gè) SelectionKey 代表了一個(gè)可以進(jìn)行 IO 操作的 channel 。

          ?????????? // 一個(gè) ServerSocketChannel 可以進(jìn)行 IO 操作意味著有新的 TCP 連接連入了

          ?????????? Set readyKeys = acceptSelector.selectedKeys();

          ?????????? Iterator i = readyKeys.iterator();

          ?

          ?????????? while (i.hasNext()) {

          ????????????? SelectionKey sk = (SelectionKey) i.next();

          ????????????? // 需要將處理過(guò)的 key selectedKeys 這個(gè)集合中刪除

          ????????????? i.remove();

          ????????????? // SelectionKey 得到對(duì)應(yīng)的 channel

          ????????????? ServerSocketChannel nextReady =

          ????????????????? (ServerSocketChannel) sk.channel();

          ????????????? // 接受新的 TCP 連接

          ????????????? Socket s = nextReady.accept().socket();

          ????????????? // 把當(dāng)前的時(shí)間寫(xiě)到這個(gè)新的 TCP 連接中

          ????????????? PrintWriter out =

          ????????????????? new PrintWriter(s.getOutputStream(), true );

          ????????????? Date now = new Date();

          ????????????? out.println(now);

          ????????????? // 關(guān)閉連接

          ????????????? out.close();

          ?????????? }

          ?????? }

          ??? }

          這是個(gè)純粹用于演示的例子,因?yàn)橹挥幸粋€(gè) ServerSocketChannel 需要監(jiān)控,所以其實(shí)并不真的需要使用到非阻塞 IO 。不過(guò)正因?yàn)樗暮?jiǎn)單,可以很容易地看清楚非阻塞 IO 是如何工作的。

          ?

          SelectableChannel

          這個(gè)抽象類(lèi)是所有支持非阻塞 IO 操作的 channel (如 DatagramChannel SocketChannel )的父類(lèi)。 SelectableChannel 可以注冊(cè)到一個(gè)或多個(gè) Selector 上以進(jìn)行非阻塞 IO 操作。

          ?

          SelectableChannel 可以是 blocking non-blocking 模式(所有 channel 創(chuàng)建的時(shí)候都是 blocking 模式),只有 non-blocking SelectableChannel 才可以參與非阻塞 IO 操作。

          ?

          SelectableChannel configureBlocking(boolean block)

          ?????? 設(shè)置 blocking 模式。

          boolean isBlocking()

          ?????? 返回 blocking 模式。

          ?

          通過(guò) register() 方法, SelectableChannel 可以注冊(cè)到 Selector 上。

          ?

          int validOps()

          返回一個(gè) bit mask ,表示這個(gè) channel 上支持的 IO 操作。當(dāng)前在 SelectionKey 中,用靜態(tài)常量定義了 4 IO 操作的 bit 值: OP_ACCEPT , OP_CONNECT OP_READ OP_WRITE

          SelectionKey register(Selector sel, int ops)

          將當(dāng)前 channel 注冊(cè)到一個(gè) Selector 上并返回對(duì)應(yīng)的 SelectionKey 。在這以后,通過(guò)調(diào)用 Selector select() 函數(shù)就可以監(jiān)控這個(gè) channel ops 這個(gè)參數(shù)是一個(gè) bit mask ,代表了需要監(jiān)控的 IO 操作。

          SelectionKey register(Selector sel, int ops, Object att)

          這個(gè)函數(shù)和上一個(gè)的意義一樣,多出來(lái)的 att 參數(shù)會(huì)作為 attachment 被存放在返回的 SelectionKey 中,這在需要存放一些 session state 的時(shí)候非常有用。

          boolean isRegistered()

          ?????? channel 是否已注冊(cè)在一個(gè)或多個(gè) Selector 上。

          ?

          SelectableChannel 還提供了得到對(duì)應(yīng) SelectionKey 的方法:

          ?

          SelectionKey keyFor(Selector sel)

          返回該 channe Selector 上的注冊(cè)關(guān)系所對(duì)應(yīng)的 SelectionKey 。若無(wú)注冊(cè)關(guān)系,返回 null

          ?

          Selector

          Selector 可以同時(shí)監(jiān)控多個(gè) SelectableChannel IO 狀況,是非阻塞 IO 的核心。

          ?

          Selector open()

          ?????? Selector 的一個(gè)靜態(tài)方法,用于創(chuàng)建實(shí)例。

          ?

          在一個(gè) Selector 中,有 3 個(gè) SelectionKey 的集合:

          1. key set 代表了所有注冊(cè)在這個(gè) Selector 上的 channel ,這個(gè)集合可以通過(guò) keys() 方法拿到。

          2. Selected-key set 代表了所有通過(guò) select() 方法監(jiān)測(cè)到可以進(jìn)行 IO 操作的 channel ,這個(gè)集合可以通過(guò) selectedKeys() 拿到。

          3. Cancelled-key set 代表了已經(jīng) cancel 了注冊(cè)關(guān)系的 channel ,在下一個(gè) select() 操作中,這些 channel 對(duì)應(yīng)的 SelectionKey 會(huì)從 key set cancelled-key set 中移走。這個(gè)集合無(wú)法直接訪(fǎng)問(wèn)。

          ?

          以下是 select() 相關(guān)方法的說(shuō)明:

          ?

          int select()

          監(jiān)控所有注冊(cè)的 channel ,當(dāng)其中有注冊(cè)的 IO 操作可以進(jìn)行時(shí),該函數(shù)返回,并將對(duì)應(yīng)的 SelectionKey 加入 selected-key set

          int select(long timeout)

          ?????? 可以設(shè)置超時(shí)的 select() 操作。

          int selectNow()

          ?????? 進(jìn)行一個(gè)立即返回的 select() 操作。

          Selector wakeup()

          ?????? 使一個(gè)還未返回的 select() 操作立刻返回。

          ?

          SelectionKey

          代表了 Selector SelectableChannel 的注冊(cè)關(guān)系。

          ?

          Selector 定義了 4 個(gè)靜態(tài)常量來(lái)表示 4 IO 操作,這些常量可以進(jìn)行位操作組合成一個(gè) bit mask

          ?

          int OP_ACCEPT

          有新的網(wǎng)絡(luò)連接可以 accept , ServerSocketChannel 支持這一非阻塞 IO 。

          int OP_CONNECT

          ?????? 代表連接已經(jīng)建立(或出錯(cuò)), SocketChannel 支持這一非阻塞 IO

          int OP_READ

          int OP_WRITE

          ?????? 代表了讀、寫(xiě)操作。

          ?

          以下是其主要方法:

          ?

          Object attachment()

          返回 SelectionKey attachment , attachment 可以在注冊(cè) channel 的時(shí)候指定。

          Object attach(Object ob)

          ?????? 設(shè)置 SelectionKey attachment

          SelectableChannel channel()

          ?????? 返回該 SelectionKey 對(duì)應(yīng)的 channel 。

          Selector selector()

          ?????? 返回該 SelectionKey 對(duì)應(yīng)的 Selector 。

          void cancel()

          ?????? cancel 這個(gè) SelectionKey 所對(duì)應(yīng)的注冊(cè)關(guān)系。

          int interestOps()

          ?????? 返回代表需要 Selector 監(jiān)控的 IO 操作的 bit mask

          SelectionKey interestOps(int ops)

          ?????? 設(shè)置 interestOps 。

          int readyOps()

          ?????? 返回一個(gè) bit mask ,代表在相應(yīng) channel 上可以進(jìn)行的 IO 操作。

          ?

          ServerSocketChannel

          支持非阻塞操作,對(duì)應(yīng)于 java.net.ServerSocket 這個(gè)類(lèi),提供了 TCP 協(xié)議 IO 接口,支持 OP_ACCEPT 操作。

          ?

          ServerSocket socket()

          ?????? 返回對(duì)應(yīng)的 ServerSocket 對(duì)象。

          SocketChannel accept()

          ?????? 接受一個(gè)連接,返回代表這個(gè)連接的 SocketChannel 對(duì)象。

          ?

          SocketChannel

          支持非阻塞操作,對(duì)應(yīng)于 java.net.Socket 這個(gè)類(lèi),提供了 TCP 協(xié)議 IO 接口,支持 OP_CONNECT , OP_READ OP_WRITE 操作。這個(gè)類(lèi)還實(shí)現(xiàn)了 ByteChannel , ScatteringByteChannel GatheringByteChannel 接口。

          DatagramChannel 和這個(gè)類(lèi)比較相似,其對(duì)應(yīng)于 java.net.DatagramSocket ,提供了 UDP 協(xié)議 IO 接口。

          ?

          Socket socket()

          ?????? 返回對(duì)應(yīng)的 Socket 對(duì)象。

          boolean connect(SocketAddress remote)

          boolean finishConnect()

          connect() 進(jìn)行一個(gè)連接操作。如果當(dāng)前 SocketChannel blocking 模式,這個(gè)函數(shù)會(huì)等到連接操作完成或錯(cuò)誤發(fā)生才返回。如果當(dāng)前 SocketChannel non-blocking 模式,函數(shù)在連接能立刻被建立時(shí)返回 true ,否則函數(shù)返回 false ,應(yīng)用程序需要在以后用 finishConnect() 方法來(lái)完成連接操作。

          ?

          Pipe

          包含了一個(gè)讀和一個(gè)寫(xiě)的 channel(Pipe.SourceChannel Pipe.SinkChannel) ,這對(duì) channel 可以用于進(jìn)程中的通訊。

          ?

          FileChannel

          用于對(duì)文件的讀、寫(xiě)、映射、鎖定等操作。和映射操作相關(guān)的類(lèi)有 FileChannel.MapMode ,和鎖定操作相關(guān)的類(lèi)有 FileLock 。值得注意的是 FileChannel 并不支持非阻塞操作。

          ?

          Channels

          這個(gè)類(lèi)提供了一系列 static 方法來(lái)支持 stream 類(lèi)和 channel 類(lèi)之間的互操作。這些方法可以將 channel 類(lèi)包裝為 stream 類(lèi),比如,將 ReadableByteChannel 包裝為 InputStream Reader ;也可以將 stream 類(lèi)包裝為 channel 類(lèi),比如,將 OutputStream 包裝為 WritableByteChannel 。

          ?

          ?

          Package java.nio.charset

          這個(gè)包定義了 Charset 及相應(yīng)的 encoder decoder 。下面這張 UML 類(lèi)圖描述了這個(gè)包中類(lèi)的關(guān)系,可以將其中 Charset CharsetDecoder CharsetEncoder 理解成一個(gè) Abstract Factory 模式的實(shí)現(xiàn):



          ?

          Charset

          代表了一個(gè)字符集,同時(shí)提供了 factory method 來(lái)構(gòu)建相應(yīng)的 CharsetDecoder CharsetEncoder 。

          ?

          Charset 提供了以下 static 的方法:

          ?

          SortedMap availableCharsets()

          ?????? 返回當(dāng)前系統(tǒng)支持的所有 Charset 對(duì)象,用 charset 的名字作為 set key 。

          boolean isSupported(String charsetName)

          ?????? 判斷該名字對(duì)應(yīng)的字符集是否被當(dāng)前系統(tǒng)支持。

          Charset forName(String charsetName)

          ?????? 返回該名字對(duì)應(yīng)的 Charset 對(duì)象。

          ?

          Charset 中比較重要的方法有:

          ?

          String name()

          ?????? 返回該字符集的規(guī)范名。

          Set aliases()

          ?????? 返回該字符集的所有別名。

          CharsetDecoder newDecoder()

          ?????? 創(chuàng)建一個(gè)對(duì)應(yīng)于這個(gè) Charset decoder 。

          CharsetEncoder newEncoder()

          ?????? 創(chuàng)建一個(gè)對(duì)應(yīng)于這個(gè) Charset encoder

          ?

          CharsetDecoder

          將按某種字符集編碼的字節(jié)流解碼為 unicode 字符數(shù)據(jù)的引擎。

          ?

          CharsetDecoder 的輸入是 ByteBuffer ,輸出是 CharBuffer 。進(jìn)行 decode 操作時(shí)一般按如下步驟進(jìn)行:

          ?

          1. 調(diào)用 CharsetDecoder reset() 方法。(第一次使用時(shí)可不調(diào)用)

          2. 調(diào)用 decode() 方法 0 n 次,將 endOfInput 參數(shù)設(shè)為 false ,告訴 decoder 有可能還有新的數(shù)據(jù)送入。

          3. 調(diào)用 decode() 方法最后一次,將 endOfInput 參數(shù)設(shè)為 true ,告訴 decoder 所有數(shù)據(jù)都已經(jīng)送入。

          4. 調(diào)用 decoder flush() 方法。讓 decoder 有機(jī)會(huì)把一些內(nèi)部狀態(tài)寫(xiě)到輸出的 CharBuffer 中。

          ?

          CharsetDecoder reset()

          ?????? 重置 decoder ,并清除 decoder 中的一些內(nèi)部狀態(tài)。

          CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput)

          ByteBuffer 類(lèi)型的輸入中 decode 盡可能多的字節(jié),并將結(jié)果寫(xiě)到 CharBuffer 類(lèi)型的輸出中。根據(jù) decode 的結(jié)果,可能返回 3 CoderResult CoderResult.UNDERFLOW 表示已經(jīng)沒(méi)有輸入可以 decode CoderResult.OVERFLOW 表示輸出已滿(mǎn);其它的 CoderResult 表示 decode 過(guò)程中有錯(cuò)誤發(fā)生。根據(jù)返回的結(jié)果,應(yīng)用程序可以采取相應(yīng)的措施,比如,增加輸入,清除輸出等等,然后再次調(diào)用 decode() 方法。

          CoderResult flush(CharBuffer out)

          有些 decoder 會(huì)在 decode 的過(guò)程中保留一些內(nèi)部狀態(tài),調(diào)用這個(gè)方法讓這些 decoder 有機(jī)會(huì)將這些內(nèi)部狀態(tài)寫(xiě)到輸出的 CharBuffer 中。調(diào)用成功返回 CoderResult.UNDERFLOW 。如果輸出的空間不夠,該函數(shù)返回 CoderResult.OVERFLOW ,這時(shí)應(yīng)用程序應(yīng)該擴(kuò)大輸出 CharBuffer 的空間,然后再次調(diào)用該方法。

          CharBuffer decode(ByteBuffer in)

          一個(gè)便捷的方法把 ByteBuffer 中的內(nèi)容 decode 到一個(gè)新創(chuàng)建的 CharBuffer 中。在這個(gè)方法中包括了前面提到的 4 個(gè)步驟,所以不能和前 3 個(gè)函數(shù)一起使用。

          ?

          decode 過(guò)程中的錯(cuò)誤有兩種: malformed-input CoderResult 表示輸入中數(shù)據(jù)有誤; unmappable-character CoderResult 表示輸入中有數(shù)據(jù)無(wú)法被解碼成 unicode 的字符。如何處理 decode 過(guò)程中的錯(cuò)誤取決于 decoder 的設(shè)置。對(duì)于這兩種錯(cuò)誤, decoder 可以通過(guò) CodingErrorAction 設(shè)置成:

          1. 忽略錯(cuò)誤

          2. 報(bào)告錯(cuò)誤。(這會(huì)導(dǎo)致錯(cuò)誤發(fā)生時(shí), decode() 方法返回一個(gè)表示該錯(cuò)誤的 CoderResult 。)

          3. 替換錯(cuò)誤,用 decoder 中的替換字串替換掉有錯(cuò)誤的部分。

          ?

          CodingErrorAction malformedInputAction()

          ?????? 返回 malformed-input 的出錯(cuò)處理。

          CharsetDecoder onMalformedInput(CodingErrorAction newAction)

          ?????? 設(shè)置 malformed-input 的出錯(cuò)處理。

          CodingErrorAction unmappableCharacterAction()

          ?????? 返回 unmappable-character 的出錯(cuò)處理。

          CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction)

          ?????? 設(shè)置 unmappable-character 的出錯(cuò)處理。

          String replacement()

          ?????? 返回 decoder 的替換字串。

          CharsetDecoder replaceWith(String newReplacement)

          ?????? 設(shè)置 decoder 的替換字串。

          ?

          CharsetEncoder

          unicode 字符數(shù)據(jù)編碼為特定字符集的字節(jié)流的引擎。其接口和 CharsetDecoder 相類(lèi)似。

          ?

          CoderResult

          描述 encode/decode 操作結(jié)果的類(lèi)。

          ?

          CodeResult 包含兩個(gè) static 成員:

          ?

          CoderResult OVERFLOW

          ?????? 表示輸出已滿(mǎn)

          CoderResult UNDERFLOW

          ?????? 表示輸入已無(wú)數(shù)據(jù)可用。

          ?

          其主要的成員函數(shù)有:

          ?

          boolean isError()

          boolean isMalformed()

          boolean isUnmappable()

          boolean isOverflow()

          boolean isUnderflow()

          ?????? 用于判斷該 CoderResult 描述的錯(cuò)誤。

          ?

          int length()

          ?????? 返回錯(cuò)誤的長(zhǎng)度,比如,無(wú)法被轉(zhuǎn)換成 unicode 的字節(jié)長(zhǎng)度。

          void throwException()

          ?????? 拋出一個(gè)和這個(gè) CoderResult 相對(duì)應(yīng)的 exception

          ?

          CodingErrorAction

          表示 encoder/decoder 中錯(cuò)誤處理方法的類(lèi)??蓪⑵淇闯梢粋€(gè) enum 類(lèi)型。有以下 static 屬性:

          ?

          CodingErrorAction IGNORE

          ?????? 忽略錯(cuò)誤。

          CodingErrorAction REPLACE

          ?????? 用替換字串替換有錯(cuò)誤的部分。

          CodingErrorAction REPORT

          報(bào)告錯(cuò)誤,對(duì)于不同的函數(shù),有可能是返回一個(gè)和錯(cuò)誤有關(guān)的 CoderResult ,也有可能是拋出一個(gè) CharacterCodingException 。

          posted on 2007-01-12 20:07 ???MengChuChen 閱讀(22297) 評(píng)論(1)  編輯  收藏

          FeedBack:
          # re: Java NIO API詳解
          2014-01-10 16:24 | nhkly

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 昆山市| 永春县| 广州市| 崇左市| 河源市| 连山| 会同县| 读书| 阜阳市| 富源县| 利辛县| 三台县| 丹东市| 和龙市| 正安县| 竹北市| 杂多县| 兴隆县| 宽城| 河间市| 融水| 佛冈县| 绩溪县| 方山县| 垣曲县| 雷波县| 永新县| 杭锦后旗| 石泉县| 漯河市| 喀喇| 黎平县| 鲁甸县| 四子王旗| 陇南市| 灵丘县| 安吉县| 大新县| 潞西市| 镇原县| 庆城县|