NIO API 主要集中在 java.nio 和它的 subpackages 中:
?
java.nio
定義了 Buffer 及其數據類型相關的子類。其中被 java.nio.channels 中的類用來進行 IO 操作的 ByteBuffer 的作用非常重要。
?
java.nio.channels
定義了一系列處理 IO 的 Channel 接口以及這些接口在文件系統和網絡通訊上的實現。通過 Selector 這個類,還提供了進行非阻塞 IO 操作的辦法。這個包可以說是 NIO API 的核心。
?
java.nio.channels.spi
定義了可用來實現 channel 和 selector API 的抽象類。
?
java.nio.charset
?????? 定義了處理字符編碼和解碼的類。
?
java.nio.charset.spi
?????? 定義了可用來實現 charset API 的抽象類。
?
java.nio.channels.spi 和 java.nio.charset.spi 這兩個包主要被用來對現有 NIO API 進行擴展,在實際的使用中,我們一般只和另外的 3 個包打交道。下面將對這 3 個包一一介紹。
?
Package java.nio
這個包主要定義了 Buffer 及其子類。 Buffer 定義了一個線性存放 primitive type 數據的容器接口。對于除 boolean 以外的其他 primitive type ,都有一個相應的 Buffer 子類, ByteBuffer 是其中最重要的一個子類。
?
下面這張 UML 類圖描述了 java.nio 中的類的關系:
?
Buffer
定義了一個可以線性存放 primitive type 數據的容器接口。 Buffer 主要包含了與類型( byte, char… )無關的功能。值得注意的是 Buffer 及其子類都不是線程安全的。
?
每個 Buffer 都有以下的屬性:
?
capacity
這個 Buffer 最多能放多少數據。 capacity 一般在 buffer 被創建的時候指定。
limit
在 Buffer 上進行的讀寫操作都不能越過這個下標。當寫數據到 buffer 中時, limit 一般和 capacity 相等,當讀數據時, limit 代表 buffer 中有效數據的長度。
position
讀 / 寫操作的當前下標。當使用 buffer 的相對位置進行讀 / 寫操作時,讀 / 寫會從這個下標進行,并在操作完成后, buffer 會更新下標的值。
mark
一個臨時存放的位置下標。調用 mark() 會將 mark 設為當前的 position 的值,以后調用 reset() 會將 position 屬性設置為 mark 的值。 mark 的值總是小于等于 position 的值,如果將 position 的值設的比 mark 小,當前的 mark 值會被拋棄掉。
?
這些屬性總是滿足以下條件:
0 <= mark <= position <= limit <= capacity
?
limit 和 position 的值除了通過 limit() 和 position() 函數來設置,也可以通過下面這些函數來改變:
?
Buffer clear()
把 position 設為 0 ,把 limit 設為 capacity ,一般在把數據寫入 Buffer 前調用。
Buffer flip()
把 limit 設為當前 position ,把 position 設為 0 ,一般在從 Buffer 讀出數據前調用。
Buffer rewind()
把 position 設為 0 , limit 不變,一般在把數據重寫入 Buffer 前調用。
?
Buffer 對象有可能是只讀的,這時,任何對該對象的寫操作都會觸發一個 ReadOnlyBufferException 。 isReadOnly() 方法可以用來判斷一個 Buffer 是否只讀。
?
ByteBuffer
在 Buffer 的子類中, ByteBuffer 是一個地位較為特殊的類,因為在 java.io.channels 中定義的各種 channel 的 IO 操作基本上都是圍繞 ByteBuffer 展開的。
?
ByteBuffer 定義了 4 個 static 方法來做創建工作:
?
ByteBuffer allocate(int capacity)
創建一個指定 capacity 的 ByteBuffer 。
ByteBuffer allocateDirect(int capacity)
創建一個 direct 的 ByteBuffer ,這樣的 ByteBuffer 在參與 IO 操作時性能會更好(很有可能是在底層的實現使用了 DMA 技術),相應的,創建和回收 direct 的 ByteBuffer 的代價也會高一些。 isDirect() 方法可以檢查一個 buffer 是否是 direct 的。
ByteBuffer wrap(byte [] array)
ByteBuffer wrap(byte [] array, int offset, int length)
把一個 byte 數組或 byte 數組的一部分包裝成 ByteBuffer 。
?
ByteBuffer 定義了一系列 get 和 put 操作來從中讀寫 byte 數據,如下面幾個:
?
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 中,也定義了相同的函數來讀寫數據,唯一不同的就是一些參數和返回值的類型。
?
除了讀寫 byte 類型數據的函數, ByteBuffer 的一個特別之處是它還定義了讀寫其它 primitive 數據的方法,如:
?
int getInt()
?????? 從 ByteBuffer 中讀出一個 int 值。
ByteBuffer putInt(int value)
?????? 寫入一個 int 值到 ByteBuffer 中。
?
讀寫其它類型的數據牽涉到字節序問題, ByteBuffer 會按其字節序(大字節序或小字節序)寫入或讀出一個其它類型的數據( int,long… )。字節序可以用 order 方法來取得和設置:
?
ByteOrder order()
?????? 返回 ByteBuffer 的字節序。
ByteBuffer order(ByteOrder bo)
?????? 設置 ByteBuffer 的字節序。
?
ByteBuffer 另一個特別的地方是可以在它的基礎上得到其它類型的 buffer 。如:
?
CharBuffer asCharBuffer()
為當前的 ByteBuffer 創建一個 CharBuffer 的視圖。在該視圖 buffer 中的讀寫操作會按照 ByteBuffer 的字節序作用到 ByteBuffer 中的數據上。
?
用這類方法創建出來的 buffer 會從 ByteBuffer 的 position 位置開始到 limit 位置結束,可以看作是這段數據的視圖。視圖 buffer 的 readOnly 屬性和 direct 屬性與 ByteBuffer 的一致,而且也只有通過這種方法,才可以得到其他數據類型的 direct buffer 。
?
ByteOrder
用來表示 ByteBuffer 字節序的類,可將其看成 java 中的 enum 類型。主要定義了下面幾個 static 方法和屬性:
?
ByteOrder BIG_ENDIAN
?????? 代表大字節序的 ByteOrder 。
ByteOrder LITTLE_ENDIAN
?????? 代表小字節序的 ByteOrder 。
ByteOrder nativeOrder()
?????? 返回當前硬件平臺的字節序。
?
MappedByteBuffer
ByteBuffer 的子類,是文件內容在內存中的映射。這個類的實例需要通過 FileChannel 的 map() 方法來創建。
?
?
接下來看看一個使用 ByteBuffer 的例子,這個例子從標準輸入不停地讀入字符,當讀滿一行后,將收集的字符寫到標準輸出:
???
public
static
void
main(String
[]
args)
??????
throws
IOException
???
{
??????
//
創建一個
capacity
為
256
的
ByteBuffer
??????
ByteBuffer
buf
=
ByteBuffer.allocate(256);
??????
while
(
true
)
{
??????????
//
從標準輸入流讀入一個字符
??????????
int
c
=
System.in.read();
??????????
//
當讀到輸入流結束時,退出循環
??????????
if
(c
==
-1)
?????????????
break
;
??????????
??????????
//
把讀入的字符寫入
ByteBuffer
中
??????????
buf.put((
byte
)
c);
??????????
//
當讀完一行時,輸出收集的字符
??????????
if
(c
==
'\n'
)
{
?????????????
//
調用
flip()
使
limit
變為當前的
position
的值
,position
變為
0,
?????????????
//
為接下來從
ByteBuffer
讀取做準備
?????????????
buf.flip();
?????????????
//
構建一個
byte
數組
?????????????
byte
[]
content
=
new
byte
[buf.limit()];
?????????????
//
從
ByteBuffer
中讀取數據到
byte
數組中
?????????????
buf.get(content);
??????????
???
//
把
byte
數組的內容寫到標準輸出
?????????????
System.out.print(
new
String(content));
?????????????
//
調用
clear()
使
position
變為
0,limit
變為
capacity
的值,
?????????????
//
為接下來寫入數據到
ByteBuffer
中做準備
?????????????
buf.clear();
??????????
}
??????
}
??? } |
?
?
Package java.nio.channels
這個包定義了 Channel 的概念, Channel 表現了一個可以進行 IO 操作的通道(比如,通過 FileChannel ,我們可以對文件進行讀寫操作)。 java.nio.channels 包含了文件系統和網絡通訊相關的 channel 類。這個包通過 Selector 和 SelectableChannel 這兩個類,還定義了一個進行非阻塞( non-blocking ) IO 操作的 API ,這對需要高性能 IO 的應用非常重要。
?
下面這張 UML 類圖描述了 java.nio.channels 中 interface 的關系:
?
Channel
Channel 表現了一個可以進行 IO 操作的通道,該 interface 定義了以下方法:
?
boolean isOpen()
?????? 該 Channel 是否是打開的。
void close()
?????? 關閉這個 Channel ,相關的資源會被釋放。
?
ReadableByteChannel
定義了一個可從中讀取 byte 數據的 channel interface 。
?
int read(ByteBuffer dst)
從 channel 中讀取 byte 數據并寫到 ByteBuffer 中。返回讀取的 byte 數。
?
WritableByteChannel
定義了一個可向其寫 byte 數據的 channel interface 。
?
int write(ByteBuffer src)
?????? 從 ByteBuffer 中讀取 byte 數據并寫到 channel 中。返回寫出的 byte 數。
?
ByteChannel
ByteChannel 并沒有定義新的方法,它的作用只是把 ReadableByteChannel 和 WritableByteChannel 合并在一起。
?
ScatteringByteChannel
繼承了 ReadableByteChannel 并提供了同時往幾個 ByteBuffer 中寫數據的能力。
?
GatheringByteChannel
繼承了 WritableByteChannel 并提供了同時從幾個 ByteBuffer 中讀數據的能力。
?
InterruptibleChannel
用來表現一個可以被異步關閉的 Channel 。這表現在兩方面:
1.??? 當一個 InterruptibleChannel 的 close() 方法被調用時,其它 block 在這個 InterruptibleChannel 的 IO 操作上的線程會接收到一個 AsynchronousCloseException 。
2.??? 當一個線程 block 在 InterruptibleChannel 的 IO 操作上時,另一個線程調用該線程的 interrupt() 方法會導致 channel 被關閉,該線程收到一個 ClosedByInterruptException ,同時線程的 interrupt 狀態會被設置。
?
?
接下來的這張 UML 類圖描述了 java.nio.channels 中類的關系:
?
非阻塞
IO
非阻塞 IO 的支持可以算是 NIO API 中最重要的功能,非阻塞 IO 允許應用程序同時監控多個 channel 以提高性能,這一功能是通過 Selector , SelectableChannel 和 SelectionKey 這 3 個類來實現的。
?
SelectableChannel 代表了可以支持非阻塞 IO 操作的 channel ,可以將其注冊在 Selector 上,這種注冊的關系由 SelectionKey 這個類來表現(見 UML 圖)。 Selector 這個類通過 select() 函數,給應用程序提供了一個可以同時監控多個 IO channel 的方法:
?
應用程序通過調用 select() 函數,讓 Selector 監控注冊在其上的多個 SelectableChannel ,當有 channel 的 IO 操作可以進行時, select() 方法就會返回以讓應用程序檢查 channel 的狀態,并作相應的處理。
?
下面是 JDK 1.4 中非阻塞 IO 的一個例子,這段 code 使用了非阻塞 IO 實現了一個 time server :
???
private
static
void
acceptConnections(
int
port)
throws
Exception
{
??????
//
打開一個
Selector
??????
Selector
acceptSelector
=
??????????
SelectorProvider.provider().openSelector();
?
??????
//
創建一個
ServerSocketChannel
,這是一個
SelectableChannel
的子類
??????
ServerSocketChannel
ssc
=
ServerSocketChannel.open();
??????
//
將其設為
non-blocking
狀態,這樣才能進行非阻塞
IO
操作
??????
ssc.configureBlocking(
false
);
?
??????
//
給
ServerSocketChannel
對應的
socket
綁定
IP
和端口
??????
InetAddress
lh
=
InetAddress.getLocalHost();
??????
InetSocketAddress
isa
=
new
InetSocketAddress(lh,
port);
??????
ssc.socket().bind(isa);
?
??????
//
將
ServerSocketChannel
注冊到
Selector
上,返回對應的
SelectionKey
??????
SelectionKey
acceptKey
=
??????????
ssc.register(acceptSelector,
SelectionKey.OP_ACCEPT);
?
??????
int
keysAdded
=
0;
?
??????
//
用
select()
函數來監控注冊在
Selector
上的
SelectableChannel
??????
//
返回值代表了有多少
channel
可以進行
IO
操作
(ready for IO)
??????
while
((keysAdded
=
acceptSelector.select())
>
0)
{
??????????
// selectedKeys()
返回一個
SelectionKey
的集合,
??????????
//
其中每個
SelectionKey
代表了一個可以進行
IO
操作的
channel
。
??????????
//
一個
ServerSocketChannel
可以進行
IO
操作意味著有新的
TCP
連接連入了
??????????
Set
readyKeys
=
acceptSelector.selectedKeys();
??????????
Iterator
i
=
readyKeys.iterator();
?
??????????
while
(i.hasNext())
{
?????????????
SelectionKey
sk
=
(SelectionKey)
i.next();
?????????????
//
需要將處理過的
key
從
selectedKeys
這個集合中刪除
?????????????
i.remove();
?????????????
//
從
SelectionKey
得到對應的
channel
?????????????
ServerSocketChannel
nextReady
=
?????????????????
(ServerSocketChannel)
sk.channel();
?????????????
//
接受新的
TCP
連接
?????????????
Socket
s
=
nextReady.accept().socket();
?????????????
//
把當前的時間寫到這個新的
TCP
連接中
?????????????
PrintWriter
out
=
?????????????????
new
PrintWriter(s.getOutputStream(),
true
);
?????????????
Date
now
=
new
Date();
?????????????
out.println(now);
?????????????
//
關閉連接
?????????????
out.close();
??????????
}
??????
}
??? } |
這是個純粹用于演示的例子,因為只有一個 ServerSocketChannel 需要監控,所以其實并不真的需要使用到非阻塞 IO 。不過正因為它的簡單,可以很容易地看清楚非阻塞 IO 是如何工作的。
?
SelectableChannel
這個抽象類是所有支持非阻塞 IO 操作的 channel (如 DatagramChannel 、 SocketChannel )的父類。 SelectableChannel 可以注冊到一個或多個 Selector 上以進行非阻塞 IO 操作。
?
SelectableChannel 可以是 blocking 和 non-blocking 模式(所有 channel 創建的時候都是 blocking 模式),只有 non-blocking 的 SelectableChannel 才可以參與非阻塞 IO 操作。
?
SelectableChannel configureBlocking(boolean block)
?????? 設置 blocking 模式。
boolean isBlocking()
?????? 返回 blocking 模式。
?
通過 register() 方法, SelectableChannel 可以注冊到 Selector 上。
?
int validOps()
返回一個 bit mask ,表示這個 channel 上支持的 IO 操作。當前在 SelectionKey 中,用靜態常量定義了 4 種 IO 操作的 bit 值: OP_ACCEPT , OP_CONNECT , OP_READ 和 OP_WRITE 。
SelectionKey register(Selector sel, int ops)
將當前 channel 注冊到一個 Selector 上并返回對應的 SelectionKey 。在這以后,通過調用 Selector 的 select() 函數就可以監控這個 channel 。 ops 這個參數是一個 bit mask ,代表了需要監控的 IO 操作。
SelectionKey register(Selector sel, int ops, Object att)
這個函數和上一個的意義一樣,多出來的 att 參數會作為 attachment 被存放在返回的 SelectionKey 中,這在需要存放一些 session state 的時候非常有用。
boolean isRegistered()
?????? 該 channel 是否已注冊在一個或多個 Selector 上。
?
SelectableChannel 還提供了得到對應 SelectionKey 的方法:
?
SelectionKey keyFor(Selector sel)
返回該 channe 在 Selector 上的注冊關系所對應的 SelectionKey 。若無注冊關系,返回 null 。
?
Selector
Selector 可以同時監控多個 SelectableChannel 的 IO 狀況,是非阻塞 IO 的核心。
?
Selector open()
?????? Selector 的一個靜態方法,用于創建實例。
?
在一個 Selector 中,有 3 個 SelectionKey 的集合:
1. key set 代表了所有注冊在這個 Selector 上的 channel ,這個集合可以通過 keys() 方法拿到。
2. Selected-key set 代表了所有通過 select() 方法監測到可以進行 IO 操作的 channel ,這個集合可以通過 selectedKeys() 拿到。
3. Cancelled-key set 代表了已經 cancel 了注冊關系的 channel ,在下一個 select() 操作中,這些 channel 對應的 SelectionKey 會從 key set 和 cancelled-key set 中移走。這個集合無法直接訪問。
?
以下是 select() 相關方法的說明:
?
int select()
監控所有注冊的 channel ,當其中有注冊的 IO 操作可以進行時,該函數返回,并將對應的 SelectionKey 加入 selected-key set 。
int select(long timeout)
?????? 可以設置超時的 select() 操作。
int selectNow()
?????? 進行一個立即返回的 select() 操作。
Selector wakeup()
?????? 使一個還未返回的 select() 操作立刻返回。
?
SelectionKey
代表了 Selector 和 SelectableChannel 的注冊關系。
?
Selector 定義了 4 個靜態常量來表示 4 種 IO 操作,這些常量可以進行位操作組合成一個 bit mask 。
?
int OP_ACCEPT
有新的網絡連接可以 accept , ServerSocketChannel 支持這一非阻塞 IO 。
int OP_CONNECT
?????? 代表連接已經建立(或出錯), SocketChannel 支持這一非阻塞 IO 。
int OP_READ
int OP_WRITE
?????? 代表了讀、寫操作。
?
以下是其主要方法:
?
Object attachment()
返回 SelectionKey 的 attachment , attachment 可以在注冊 channel 的時候指定。
Object attach(Object ob)
?????? 設置 SelectionKey 的 attachment 。
SelectableChannel channel()
?????? 返回該 SelectionKey 對應的 channel 。
Selector selector()
?????? 返回該 SelectionKey 對應的 Selector 。
void cancel()
?????? cancel 這個 SelectionKey 所對應的注冊關系。
int interestOps()
?????? 返回代表需要 Selector 監控的 IO 操作的 bit mask 。
SelectionKey interestOps(int ops)
?????? 設置 interestOps 。
int readyOps()
?????? 返回一個 bit mask ,代表在相應 channel 上可以進行的 IO 操作。
?
ServerSocketChannel
支持非阻塞操作,對應于 java.net.ServerSocket 這個類,提供了 TCP 協議 IO 接口,支持 OP_ACCEPT 操作。
?
ServerSocket socket()
?????? 返回對應的 ServerSocket 對象。
SocketChannel accept()
?????? 接受一個連接,返回代表這個連接的 SocketChannel 對象。
?
SocketChannel
支持非阻塞操作,對應于 java.net.Socket 這個類,提供了 TCP 協議 IO 接口,支持 OP_CONNECT , OP_READ 和 OP_WRITE 操作。這個類還實現了 ByteChannel , ScatteringByteChannel 和 GatheringByteChannel 接口。
DatagramChannel 和這個類比較相似,其對應于 java.net.DatagramSocket ,提供了 UDP 協議 IO 接口。
?
Socket socket()
?????? 返回對應的 Socket 對象。
boolean connect(SocketAddress remote)
boolean finishConnect()
connect() 進行一個連接操作。如果當前 SocketChannel 是 blocking 模式,這個函數會等到連接操作完成或錯誤發生才返回。如果當前 SocketChannel 是 non-blocking 模式,函數在連接能立刻被建立時返回 true ,否則函數返回 false ,應用程序需要在以后用 finishConnect() 方法來完成連接操作。
?
Pipe
包含了一個讀和一個寫的 channel(Pipe.SourceChannel 和 Pipe.SinkChannel) ,這對 channel 可以用于進程中的通訊。
?
FileChannel
用于對文件的讀、寫、映射、鎖定等操作。和映射操作相關的類有 FileChannel.MapMode ,和鎖定操作相關的類有 FileLock 。值得注意的是 FileChannel 并不支持非阻塞操作。
?
Channels
這個類提供了一系列 static 方法來支持 stream 類和 channel 類之間的互操作。這些方法可以將 channel 類包裝為 stream 類,比如,將 ReadableByteChannel 包裝為 InputStream 或 Reader ;也可以將 stream 類包裝為 channel 類,比如,將 OutputStream 包裝為 WritableByteChannel 。
?
?
Package java.nio.charset
這個包定義了 Charset 及相應的 encoder 和 decoder 。下面這張 UML 類圖描述了這個包中類的關系,可以將其中 Charset , CharsetDecoder 和 CharsetEncoder 理解成一個 Abstract Factory 模式的實現:
?
Charset
代表了一個字符集,同時提供了 factory method 來構建相應的 CharsetDecoder 和 CharsetEncoder 。
?
Charset 提供了以下 static 的方法:
?
SortedMap availableCharsets()
?????? 返回當前系統支持的所有 Charset 對象,用 charset 的名字作為 set 的 key 。
boolean isSupported(String charsetName)
?????? 判斷該名字對應的字符集是否被當前系統支持。
Charset forName(String charsetName)
?????? 返回該名字對應的 Charset 對象。
?
Charset 中比較重要的方法有:
?
String name()
?????? 返回該字符集的規范名。
Set aliases()
?????? 返回該字符集的所有別名。
CharsetDecoder newDecoder()
?????? 創建一個對應于這個 Charset 的 decoder 。
CharsetEncoder newEncoder()
?????? 創建一個對應于這個 Charset 的 encoder 。
?
CharsetDecoder
將按某種字符集編碼的字節流解碼為 unicode 字符數據的引擎。
?
CharsetDecoder 的輸入是 ByteBuffer ,輸出是 CharBuffer 。進行 decode 操作時一般按如下步驟進行:
?
1. 調用 CharsetDecoder 的 reset() 方法。(第一次使用時可不調用)
2. 調用 decode() 方法 0 到 n 次,將 endOfInput 參數設為 false ,告訴 decoder 有可能還有新的數據送入。
3. 調用 decode() 方法最后一次,將 endOfInput 參數設為 true ,告訴 decoder 所有數據都已經送入。
4. 調用 decoder 的 flush() 方法。讓 decoder 有機會把一些內部狀態寫到輸出的 CharBuffer 中。
?
CharsetDecoder reset()
?????? 重置 decoder ,并清除 decoder 中的一些內部狀態。
CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput)
從 ByteBuffer 類型的輸入中 decode 盡可能多的字節,并將結果寫到 CharBuffer 類型的輸出中。根據 decode 的結果,可能返回 3 種 CoderResult : CoderResult.UNDERFLOW 表示已經沒有輸入可以 decode ; CoderResult.OVERFLOW 表示輸出已滿;其它的 CoderResult 表示 decode 過程中有錯誤發生。根據返回的結果,應用程序可以采取相應的措施,比如,增加輸入,清除輸出等等,然后再次調用 decode() 方法。
CoderResult flush(CharBuffer out)
有些 decoder 會在 decode 的過程中保留一些內部狀態,調用這個方法讓這些 decoder 有機會將這些內部狀態寫到輸出的 CharBuffer 中。調用成功返回 CoderResult.UNDERFLOW 。如果輸出的空間不夠,該函數返回 CoderResult.OVERFLOW ,這時應用程序應該擴大輸出 CharBuffer 的空間,然后再次調用該方法。
CharBuffer decode(ByteBuffer in)
一個便捷的方法把 ByteBuffer 中的內容 decode 到一個新創建的 CharBuffer 中。在這個方法中包括了前面提到的 4 個步驟,所以不能和前 3 個函數一起使用。
?
decode 過程中的錯誤有兩種: malformed-input CoderResult 表示輸入中數據有誤; unmappable-character CoderResult 表示輸入中有數據無法被解碼成 unicode 的字符。如何處理 decode 過程中的錯誤取決于 decoder 的設置。對于這兩種錯誤, decoder 可以通過 CodingErrorAction 設置成:
1. 忽略錯誤
2. 報告錯誤。(這會導致錯誤發生時, decode() 方法返回一個表示該錯誤的 CoderResult 。)
3. 替換錯誤,用 decoder 中的替換字串替換掉有錯誤的部分。
?
CodingErrorAction malformedInputAction()
?????? 返回 malformed-input 的出錯處理。
CharsetDecoder onMalformedInput(CodingErrorAction newAction)
?????? 設置 malformed-input 的出錯處理。
CodingErrorAction unmappableCharacterAction()
?????? 返回 unmappable-character 的出錯處理。
CharsetDecoder onUnmappableCharacter(CodingErrorAction newAction)
?????? 設置 unmappable-character 的出錯處理。
String replacement()
?????? 返回 decoder 的替換字串。
CharsetDecoder replaceWith(String newReplacement)
?????? 設置 decoder 的替換字串。
?
CharsetEncoder
將 unicode 字符數據編碼為特定字符集的字節流的引擎。其接口和 CharsetDecoder 相類似。
?
CoderResult
描述 encode/decode 操作結果的類。
?
CodeResult 包含兩個 static 成員:
?
CoderResult OVERFLOW
?????? 表示輸出已滿
CoderResult UNDERFLOW
?????? 表示輸入已無數據可用。
?
其主要的成員函數有:
?
boolean isError()
boolean isMalformed()
boolean isUnmappable()
boolean isOverflow()
boolean isUnderflow()
?????? 用于判斷該 CoderResult 描述的錯誤。
?
int length()
?????? 返回錯誤的長度,比如,無法被轉換成 unicode 的字節長度。
void throwException()
?????? 拋出一個和這個 CoderResult 相對應的 exception 。
?
CodingErrorAction
表示 encoder/decoder 中錯誤處理方法的類??蓪⑵淇闯梢粋€ enum 類型。有以下 static 屬性:
?
CodingErrorAction IGNORE
?????? 忽略錯誤。
CodingErrorAction REPLACE
?????? 用替換字串替換有錯誤的部分。
CodingErrorAction REPORT
報告錯誤,對于不同的函數,有可能是返回一個和錯誤有關的 CoderResult ,也有可能是拋出一個 CharacterCodingException 。