Java NIO:NIO概述
在上一篇博文中講述了幾種IO模型,現在我們開始進入Java NIO程式設計主題。NIO是Java 4裡面提供的新的API,目的是用來解決傳統IO的問題。本文下面分别從Java NIO的幾個基礎概念介紹起。
以下是本文的目錄大綱:
一.NIO中的幾個基礎概念
二.Channel
三.Buffer
四.Selector
若有不正之處,請多多諒解并歡迎批評指正。
請尊重作者勞動成果,轉載請标明原文連結:
http://www.cnblogs.com/dolphin0520/p/3919162.html
在NIO中有幾個比較關鍵的概念:Channel(通道),Buffer(緩沖區),Selector(選擇器)。
首先從Channel說起吧,通道,顧名思義,就是通向什麼的道路,為某個提供了管道。在傳統IO中,我們要讀取一個檔案中的内容,通常是像下面這樣讀取的:
1
2
3
4
5
6
7
8
9
<code>public</code> <code>class</code> <code>Test {</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) </code><code>throws</code> <code>IOException {</code>
<code> </code><code>File file = </code><code>new</code> <code>File(</code><code>"data.txt"</code><code>);</code>
<code> </code><code>InputStream inputStream = </code><code>new</code> <code>FileInputStream(file);</code>
<code> </code><code>byte</code><code>[] bytes = </code><code>new</code> <code>byte</code><code>[</code><code>1024</code><code>];</code>
<code> </code><code>inputStream.read(bytes);</code>
<code> </code><code>inputStream.close();</code>
<code> </code><code>} </code>
<code>}</code>
這裡的InputStream實際上就是為讀取檔案提供一個通道的。
是以可以将NIO 中的Channel同傳統IO中的Stream來類比,但是要注意,傳統IO中,Stream是單向的,比如InputStream隻能進行讀取操作,OutputStream隻能進行寫操作。而Channel是雙向的,既可用來進行讀操作,又可用來進行寫操作。
Buffer(緩沖區),是NIO中非常重要的一個東西,在NIO中所有資料的讀和寫都離不開Buffer。比如上面的一段代碼中,讀取的資料時放在byte數組當中,而在NIO中,讀取的資料隻能放在Buffer中。同樣地,寫入資料也是先寫入到Buffer中。
下面介紹一下NIO中最核心的一個東西:Selector。可以說它是NIO中最關鍵的一個部分,Selector的作用就是用來輪詢每個注冊的Channel,一旦發現Channel有注冊的事件發生,便擷取事件然後進行處理。
比如看下面的這個例子:

用單線程處理一個Selector,然後通過Selector.select()方法來擷取到達事件,在擷取了到達事件之後,就可以逐個地對這些事件進行響應處理。
在前面已經提到,Channel和傳統IO中的Stream很相似。雖然很相似,但是有很大的差別,主要差別為:通道是雙向的,通過一個Channel既可以進行讀,也可以進行寫;而Stream隻能進行單向操作,通過一個Stream隻能進行讀或者寫;
以下是常用的幾種通道:
FileChannel
SocketChanel
ServerSocketChannel
DatagramChannel
通過使用FileChannel可以從檔案讀或者向檔案寫入資料;通過SocketChannel,以TCP來向網絡連接配接的兩端讀寫資料;通過ServerSocketChanel能夠監聽用戶端發起的TCP連接配接,并為每個TCP連接配接建立一個新的SocketChannel來進行資料讀寫;通過DatagramChannel,以UDP協定來向網絡連接配接的兩端讀寫資料。
下面給出通過FileChannel來向檔案中寫入資料的一個例子:
10
11
12
13
14
<code> </code><code>FileOutputStream outputStream = </code><code>new</code> <code>FileOutputStream(file);</code>
<code> </code><code>FileChannel channel = outputStream.getChannel();</code>
<code> </code><code>ByteBuffer buffer = ByteBuffer.allocate(</code><code>1024</code><code>);</code>
<code> </code><code>String string = </code><code>"java nio"</code><code>;</code>
<code> </code><code>buffer.put(string.getBytes());</code>
<code> </code><code>buffer.flip(); </code><code>//此處必須要調用buffer的flip方法</code>
<code> </code><code>channel.write(buffer);</code>
<code> </code><code>channel.close();</code>
<code> </code><code>outputStream.close();</code>
通過上面的程式會向工程目錄下的data.txt檔案寫入字元串"java nio",注意在調用channel的write方法之前必須調用buffer的flip方法,否則無法正确寫入内容,至于具體原因将在下篇博文中具體講述Buffer的用法時闡述。
Buffer,故名思意,緩沖區,實際上是一個容器,是一個連續數組。Channel提供從檔案、網絡讀取資料的管道,但是讀取或寫入的資料都必須經由Buffer。具體看下面這張圖就了解了:
上面的圖描述了從一個用戶端向服務端發送資料,然後服務端接收資料的過程。用戶端發送資料時,必須先将資料存入Buffer中,然後将Buffer中的内容寫入通道。服務端這邊接收資料必須通過Channel将資料讀入到Buffer中,然後再從Buffer中取出資料來處理。
在NIO中,Buffer是一個頂層父類,它是一個抽象類,常用的Buffer的子類有:
ByteBuffer
IntBuffer
CharBuffer
LongBuffer
DoubleBuffer
FloatBuffer
ShortBuffer
如果是對于檔案讀寫,上面幾種Buffer都可能會用到。但是對于網絡讀寫來說,用的最多的是ByteBuffer。
關于Buffer的具體使用以及它的limit、posiion和capacity這幾個屬性的了解在下一篇文章中講述。
Selector類是NIO的核心類,Selector能夠檢測多個注冊的通道上是否有事件發生,如果有事件發生,便擷取事件然後針對每個事件進行相應的響應處理。這樣一來,隻是用一個單線程就可以管理多個通道,也就是管理多個連接配接。這樣使得隻有在連接配接真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少了系統開銷,并且不必為每個連接配接都建立一個線程,不用去維護多個線程,并且避免了多線程之間的上下文切換導緻的開銷。
與Selector有關的一個關鍵類是SelectionKey,一個SelectionKey表示一個到達的事件,這2個類構成了服務端處理業務的關鍵邏輯。
關于Selector類的具體使用将在後續文章中闡述。
參考資料:
本文轉載自海 子部落格園部落格,原文連結:http://www.cnblogs.com/dolphin0520/p/3919162.html如需轉載自行聯系原作者