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

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

          ?

          java.nio

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

          ?

          java.nio.channels

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

          ?

          java.nio.channels.spi

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

          ?

          java.nio.charset

          ?????? 定義了處理字符編碼和解碼的類。

          ?

          java.nio.charset.spi

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

          ?

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

          ?

          Package java.nio

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

          ?

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



          ?

          Buffer

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

          ?

          每個 Buffer 都有以下的屬性:

          ?

          capacity

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

          limit

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

          position

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

          mark

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

          ?

          這些屬性總是滿足以下條件:

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

          ?

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

          ?

          Buffer clear()

          position 設(shè)為 0 ,把 limit 設(shè)為 capacity ,一般在把數(shù)據(jù)寫入 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ù)重寫入 Buffer 前調(diào)用。

          ?

          Buffer 對象有可能是只讀的,這時,任何對該對象的寫操作都會觸發(fā)一個 ReadOnlyBufferException isReadOnly() 方法可以用來判斷一個 Buffer 是否只讀。

          ?

          ByteBuffer

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

          ?

          ByteBuffer 定義了 4 static 方法來做創(chuàng)建工作:

          ?

          ByteBuffer allocate(int capacity)

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

          ByteBuffer allocateDirect(int capacity)

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

          ByteBuffer wrap(byte [] array)

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

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

          ?

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

          ?

          byte get()

          ByteBuffer get(byte [] dst)

          byte get(int index)

          ?

          ByteBuffer put(byte b)

          ByteBuffer put(byte [] src)

          ByteBuffer put(int index, byte b)

          ?

          這些操作可分為絕對定位和相對定為兩種,相對定位的讀寫操作依靠 position 來定位 Buffer 中的位置,并在操作完成后會更新 position 的值。

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

          ?

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

          ?

          int getInt()

          ?????? ByteBuffer 中讀出一個 int 值。

          ByteBuffer putInt(int value)

          ?????? 寫入一個 int 值到 ByteBuffer 中。

          ?

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

          ?

          ByteOrder order()

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

          ByteBuffer order(ByteOrder bo)

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

          ?

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

          ?

          CharBuffer asCharBuffer()

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

          ?

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

          ?

          ByteOrder

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

          ?

          ByteOrder BIG_ENDIAN

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

          ByteOrder LITTLE_ENDIAN

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

          ByteOrder nativeOrder()

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

          ?

          MappedByteBuffer

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

          ?

          ?

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

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

          ?????? throws IOException

          ??? {

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

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

          ?????? while ( true ) {

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

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

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

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

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

          ??????????

          ?????????? // 把讀入的字符寫入 ByteBuffer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

          ?????????? }

          ?????? }

          ??? }

          ?

          ?

          Package java.nio.channels

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

          ?

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



          ?

          Channel

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

          ?

          boolean isOpen()

          ?????? Channel 是否是打開的。

          void close()

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

          ?

          ReadableByteChannel

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

          ?

          int read(ByteBuffer dst)

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

          ?

          WritableByteChannel

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

          ?

          int write(ByteBuffer src)

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

          ?

          ByteChannel

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

          ?

          ScatteringByteChannel

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

          ?

          GatheringByteChannel

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

          ?

          InterruptibleChannel

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

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

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

          ?

          ?

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



          ?

          非阻塞 IO

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

          ?

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

          ?

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

          ?

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

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

          ?????? // 打開一個 Selector

          ?????? Selector acceptSelector =

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

          ?

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

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

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

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

          ?

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

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

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

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

          ?

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

          ?????? SelectionKey acceptKey =

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

          ?

          ?????? int keysAdded = 0;

          ?

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

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

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

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

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

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

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

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

          ?

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

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

          ????????????? // 需要將處理過的 key selectedKeys 這個集合中刪除

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

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

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

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

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

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

          ????????????? // 把當(dāng)前的時間寫到這個新的 TCP 連接中

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

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

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

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

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

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

          ?????????? }

          ?????? }

          ??? }

          這是個純粹用于演示的例子,因?yàn)橹挥幸粋€ ServerSocketChannel 需要監(jiān)控,所以其實(shí)并不真的需要使用到非阻塞 IO 。不過正因?yàn)樗暮唵危梢院苋菀椎乜辞宄亲枞?/span> IO 是如何工作的。

          ?

          SelectableChannel

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

          ?

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

          ?

          SelectableChannel configureBlocking(boolean block)

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

          boolean isBlocking()

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

          ?

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

          ?

          int validOps()

          返回一個 bit mask ,表示這個 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 注冊到一個 Selector 上并返回對應(yīng)的 SelectionKey 。在這以后,通過調(diào)用 Selector select() 函數(shù)就可以監(jiān)控這個 channel ops 這個參數(shù)是一個 bit mask ,代表了需要監(jiān)控的 IO 操作。

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

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

          boolean isRegistered()

          ?????? channel 是否已注冊在一個或多個 Selector 上。

          ?

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

          ?

          SelectionKey keyFor(Selector sel)

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

          ?

          Selector

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

          ?

          Selector open()

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

          ?

          在一個 Selector 中,有 3 SelectionKey 的集合:

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

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

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

          ?

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

          ?

          int select()

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

          int select(long timeout)

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

          int selectNow()

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

          Selector wakeup()

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

          ?

          SelectionKey

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

          ?

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

          ?

          int OP_ACCEPT

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

          int OP_CONNECT

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

          int OP_READ

          int OP_WRITE

          ?????? 代表了讀、寫操作。

          ?

          以下是其主要方法:

          ?

          Object attachment()

          返回 SelectionKey attachment attachment 可以在注冊 channel 的時候指定。

          Object attach(Object ob)

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

          SelectableChannel channel()

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

          Selector selector()

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

          void cancel()

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

          int interestOps()

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

          SelectionKey interestOps(int ops)

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

          int readyOps()

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

          ?

          ServerSocketChannel

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

          ?

          ServerSocket socket()

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

          SocketChannel accept()

          ?????? 接受一個連接,返回代表這個連接的 SocketChannel 對象。

          ?

          SocketChannel

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

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

          ?

          Socket socket()

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

          boolean connect(SocketAddress remote)

          boolean finishConnect()

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

          ?

          Pipe

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

          ?

          FileChannel

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

          ?

          Channels

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

          ?

          ?

          Package java.nio.charset

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



          ?

          Charset

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

          ?

          Charset 提供了以下 static 的方法:

          ?

          SortedMap availableCharsets()

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

          boolean isSupported(String charsetName)

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

          Charset forName(String charsetName)

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

          ?

          Charset 中比較重要的方法有:

          ?

          String name()

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

          Set aliases()

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

          CharsetDecoder newDecoder()

          ?????? 創(chuàng)建一個對應(yīng)于這個 Charset decoder

          CharsetEncoder newEncoder()

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

          ?

          CharsetDecoder

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

          ?

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

          ?

          1. 調(diào)用 CharsetDecoder reset() 方法。(第一次使用時可不調(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ī)會把一些內(nèi)部狀態(tài)寫到輸出的 CharBuffer 中。

          ?

          CharsetDecoder reset()

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

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

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

          CoderResult flush(CharBuffer out)

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

          CharBuffer decode(ByteBuffer in)

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

          ?

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

          1. 忽略錯誤

          2. 報告錯誤。(這會導(dǎo)致錯誤發(fā)生時, decode() 方法返回一個表示該錯誤的 CoderResult 。)

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

          ?

          CodingErrorAction malformedInputAction()

          ?????? 返回 malformed-input 的出錯處理。

          CharsetDecoder onMalformedInput(CodingErrorAction newAction)

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

          CodingErrorAction unmappableCharacterAction()

          ?????? 返回 unmappable-character 的出錯處理。

          CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction)

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

          String replacement()

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

          CharsetDecoder replaceWith(String newReplacement)

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

          ?

          CharsetEncoder

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

          ?

          CoderResult

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

          ?

          CodeResult 包含兩個 static 成員:

          ?

          CoderResult OVERFLOW

          ?????? 表示輸出已滿

          CoderResult UNDERFLOW

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

          ?

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

          ?

          boolean isError()

          boolean isMalformed()

          boolean isUnmappable()

          boolean isOverflow()

          boolean isUnderflow()

          ?????? 用于判斷該 CoderResult 描述的錯誤。

          ?

          int length()

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

          void throwException()

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

          ?

          CodingErrorAction

          表示 encoder/decoder 中錯誤處理方法的類。可將其看成一個 enum 類型。有以下 static 屬性:

          ?

          CodingErrorAction IGNORE

          ?????? 忽略錯誤。

          CodingErrorAction REPLACE

          ?????? 用替換字串替換有錯誤的部分。

          CodingErrorAction REPORT

          報告錯誤,對于不同的函數(shù),有可能是返回一個和錯誤有關(guān)的 CoderResult ,也有可能是拋出一個 CharacterCodingException

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

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

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 南通市| 利津县| 房山区| 桂林市| 南通市| 莱阳市| 庆元县| 孝感市| 江油市| 石景山区| 南昌市| 南部县| 兴业县| 田东县| 遵义市| 济阳县| 灵宝市| 仙居县| 保德县| 望谟县| 佛山市| 克东县| 泸西县| 莆田市| 浪卡子县| 建湖县| 武功县| 新巴尔虎左旗| 科技| 分宜县| 兰州市| 迁西县| 沂水县| 峨眉山市| 和龙市| 泗水县| 乐昌市| 西昌市| 武鸣县| 彭州市| 来凤县|