java_IO流之 NIO
NIO 定義
即新IO,在JDK1.4的java.nio.*包中引入,其目的在于提高速度。
在Java1.4之前的I/O系統中,提供的都是面向流的I/O系統,系統一次一個字節地處理數據,一個輸入流產生一個字節的數據,一個輸出流消費一個字節的數據,面向流的I/O速度非常慢,而在Java 1.4中推出了NIO,這是一個面向塊的I/O系統,系統以塊的方式處理處理,每一個操作在一步中產生或者消費一個數據庫,按塊處理要比按字節處理數據快的多。
速度的提高來自于所使用的結構更接近于操作系統執行IO的方式:通道和緩沖期。我們可以把它想象成一個煤礦,通道是一個包含煤層(數據)的礦藏,而緩沖器則是派送到礦藏的卡車。卡車滿載煤炭而歸,我們再從卡車上獲得煤炭。也就說,我們并沒有直接好通道交互,我們只和緩沖區交互。
緩沖區(Buffer)
緩沖區本質上是一塊可以寫入數據,然后可以從中讀取數據的內存。這塊內存被包裝成NIO Buffer對象,并提供了一組方法,用來方便的訪問該塊內存。,在NIO庫中,所有數據都是用緩沖區處理的。在讀取數據時,它是直接讀到緩沖區中的; 在寫入數據時,它也是寫入到緩沖區中的;任何時候訪問 NIO 中的數據,都是將它放到緩沖區中。而在面向流I/O系統中,所有數據都是直接寫入或者直接將數據讀取到Stream對象中。
在NIO中,所有的緩沖區類型都繼承于抽象類Buffer,最常用的就是ByteBuffer,對于Java中的基本類型,基本都有一個具體Buffer類型與之相對應,它們之間的繼承關系如下圖所示:
Buffer基本用法
使用Buffer讀寫數據一般遵循以下四個步驟:
當向buffer寫入數據時,buffer會記錄下寫了多少數據。一旦要讀取數據,需要通過flip()方法將Buffer從寫模式切換到讀模式。在讀模式下,可以讀取之前寫入到buffer的所有數據。
一旦讀完了所有的數據,就需要清空緩沖區,讓它可以再次被寫入。有兩種方式能清空緩沖區:調用clear()或compact()方法。clear()方法會清空整個緩沖區。compact()方法只會清除已經讀過的數據。任何未讀的數據都被移到緩沖區的起始處,新寫入的數據將放到緩沖區未讀數據的后面。
通道(Channel)
通道是一個對象,通過它可以讀取和寫入數據,當然了所有數據都通過Buffer對象來處理。我們永遠不會將字節直接寫入通道中,相反是將數據寫入包含一個或者多個字節的緩沖區。同樣不會直接從通道中讀取字節,而是將數據從通道讀入緩沖區,再從緩沖區獲取這個字節。
通道類似流,但又有些不同:
- 既可以從通道中讀取數據,又可以寫數據到通道。但流的讀寫通常是單向的。
- 通道可以異步讀寫
- 通道中數據總要先讀到Buffer,或者從一個Buffer寫入
這個圖看著好混亂,那我們講幾個比較重要的通道:
- FileChannel : 從文件中讀寫數據。
- DatagramChannel :通過UDP讀寫網絡中的數據。
- SocketChannel :通過TCP讀寫網絡中的數據。
- ServerSocketChannel: 監聽新進來的TCP連接,像Web服務器那樣。對每一個新進來的連接都會創建一個SocketChannel。
Channel基本用法
為了說明,下面舉個讀文件的例子。
public static void main(String[] args) {try {FileInputStream fin = new FileInputStream("test.txt");// get channelFileChannel fc = fin.getChannel();// bufferByteBuffer buffer = ByteBuffer.allocate(1024);//read data to bufferfc.read(buffer);buffer.flip();while(buffer.remaining()>0){byte b = buffer.get();System.out.print((char)b);}fin.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}阻塞IO(常規IO) VS 非阻塞IO(NIO)
- Java IO的各種流是阻塞的。這意味著,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再干任何事情了。
- Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什么都不會獲取。而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情;非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閑時間用于在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。
所以這就引入一個概念,選擇器
選擇器(Selectors)
Selector允許單線程處理多個 Channel。如果你的應用打開了多個連接(通道),但每個連接的流量都很低,使用Selector就會很方便。
你可以注冊多個通道使用一個選擇器,然后使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。
使用
要使用Selector,得向Selector注冊Channel,然后調用它的select()方法。這個方法會一直阻塞到某個注冊的通道有事件就緒。一旦這個方法返回,線程就可以處理這些事件,事件的例子有如新連接進來,數據接收等。
轉載于:https://www.cnblogs.com/tina-smile/p/5245326.html
總結
以上是生活随笔為你收集整理的java_IO流之 NIO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 梦到流产是什么意思
- 下一篇: python Pillow 的简单案例