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 。