NIO相關基礎篇一

轉載請註明原創出處,謝謝!java

說在前面

NIO相關知識是不少後續的一些基礎知識,因此今天這篇文章僅僅是簡單介紹,後續會繼續有一到二篇相關NIO內容。數組

什麼是NIO

Java NIO( New IO) 是從Java 1.4版本開始引入的一個新的IO API,能夠替代標準的Java IO API。NIO與原來的IO有一樣的做用和目的,可是使用的方式徹底不一樣, NIO支持面向緩衝區的、基於通道的IO操做。 NIO將以更加高效的方式進行文件的讀寫操做。緩存

NIO與普通IO的主要區別

IO NIO
面向流(Stream Oriented) 面向緩衝區(Buffer Oriented)
阻塞IO(Blocking IO) 非阻塞IO(Non Blocking IO)
(無) 選擇器(Selectors)
  • Channels and Buffers(通道和緩衝區):標準的IO基於字節流和字符流進行操做的,而NIO是基於通道(Channel)和緩衝區(Buffer)進行操做,數據老是從通道讀取到緩衝區中,或者從緩衝區寫入到通道中。
  • Asynchronous IO(異步IO):Java NIO可讓你異步的使用IO,例如:當線程從通道讀取數據到緩衝區時,線程仍是能夠進行其餘事情。當數據被寫入到緩衝區時,線程能夠繼續處理它。從緩衝區寫入通道也相似。
  • Selectors(選擇器):Java NIO引入了選擇器的概念,選擇器用於監聽多個通道的事件(好比:鏈接打開,數據到達)。所以,單個的線程能夠監聽多個數據通道。

**說明:**Asynchronous IO(異步IO)、Selectors(選擇器)等後續文章會繼續介紹的。網絡

緩衝區(Buffer)

經過上面NIO與普通IO的主要區別也能夠看到在基本的IO操做中全部的操做都是基於流進行操做的,而在NIO中全部的操做都是基於緩衝區繼續操做的,全部的讀寫操做都是經過緩存區來進行完成,緩衝區(Buffer)是一個線性的、有序的數據集,只能容納特定的數據類型(基本就是基本數據類型對應的Buffer或者起子類)。dom

各各數據類型的緩存區類

緩存區類 相關描述
ByteBuffer 存儲字節的Buffer
CharBuffer 存儲字符的Buffer
ShortBuffer 存儲短整型的Buffer
IntBuffer 存儲整型的Buffer
LongBuffer 存儲長整型的Buffer
FloatBuffer 存儲單精度浮點型Buffer
DoubleBuffer 存儲雙精度浮點型Buffer

**備註:**看到上面這幾類是否是想起了JAVA的8種基本數據類型,惟一缺乏boolean對於的類型。異步

第一問:爲何boolean不須要緩存呢? 能夠查閱以前寫的:java二進制相關基礎,裏面有描述規範中數字的內部表示和存儲,boolean所佔位數1bit(取值只有true或者false),因爲字節(byte)是操做系統和全部I/O設備使用的基本數據類型,因此基本都是以字節或者連續的一段字節來存儲表示,因此就沒有boolean,感受也沒有必要boolean類型的緩存操做(像RocketMQ源碼裏面可能把一個Int裏面的某位來表示boolean,其餘位繼續來存儲數據,歡迎關注個人公衆號【匠心零度】,後續RocketMQ源碼類分析的時候如何運用上述技巧進行說明等,其實上面我寫的好幾篇文章都是爲了後續RocketMQ源碼分析作準備的)。源碼分析

Buffer使用

讀數據:post

  • flip()方法
    • 將Buffer從寫模式切換到讀模式
    • 調用flip()方法會將position設回0,並將limit設置成以前position的值。
    • buf.flip();
  • buf.get()
    • 讀取數據
  • Buffer.rewind()
    • 將position設回0,因此你能夠重讀Buffer中的全部數據
    • limit保持不變,仍然表示能從Buffer中讀取多少個元素(byte、char等)
  • Buffer.mark()方法,能夠標記Buffer中的一個特定position。以後能夠經過調用。
  • Buffer.reset()方法,恢復到Buffer.mark()標記時的position。
  • clear()方法會:
    • 清空整個緩衝區。
    • position將被設回0,limit被設置成 capacity的值
  • compact()方法:
    • 只會清除已經讀過的數據;任何未讀的數據都被移到緩衝區的起始處,新寫入的數據將放到緩衝區未讀數據的後面。
    • 將position設到最後一個未讀元素正後面,limit被設置成 capacity的值。

寫數據: buf.put(127);大數據

緩衝區的基本屬性

  • 容量 (capacity):表示 Buffer 最大數據容量,緩衝區容量不能爲負,而且建立後不能更改。
  • 限制 (limit):第一個不該該讀取或寫入的數據的索引,即位於 limit 後的數據不可讀寫。緩衝區的限制不能爲負,而且不能大於其容量。
  • 位置 (position):下一個要讀取或寫入的數據的索引。緩衝區的位置不能爲負,而且不能大於其限制。

**備註:**標記、 位置、 限制、 容量遵照如下不變式: 0 <= position <= limit <= capacity。spa

爲了更形象解釋上面重要屬性,準備配上簡單代碼以及圖來進行說明就容易懂了。

//第一步,獲取IntBuffer,經過IntBuffer.allocate操做
IntBuffer buf = IntBuffer.allocate(10) ;	// 準備出10個大小的緩衝區

//第二步未操做前輸出屬性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;

//第三步進行設置數據
buf.put(6) ;	// 設置一個數據
buf.put(16) ;	// 設置二個數據

//第四步操做後輸出屬性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;

//第五步將Buffer從寫模式切換到讀模式 postion = 0 ,limit = 本來position
buf.flip() ;	 

//第六步操做後輸出屬性值
System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " + buf.capacity()) ;
複製代碼

程序輸出結果:

position = 0,limit = 10,capacty = 10
position = 2,limit = 10,capacty = 10
position = 0,limit = 2,capacty = 10
複製代碼

查看下圖來進行說明:

通道(Channel)

通道表示打開到 IO 設備(例如:文件、套接字)的鏈接。若須要使用 NIO 系統,須要獲取用於鏈接 IO 設備的通道以及用於容納數據的緩衝區。而後操做緩衝區,對數據進行處理。Channel 負責傳輸, Buffer 負責存儲。通道是由 java.nio.channels 包定義的。 Channel 表示 IO 源與目標打開的鏈接。Channel 相似於傳統的「流」。只不過 Channel自己不能直接訪問數據, Channel 只能與Buffer 進行交互。

通道都是操做緩存區完成所有的功能的。

Java中全部已知 Channel 實現類:

  • AbstractInterruptibleChannel
  • AbstractSelectableChannel
  • DatagramChannel
  • FileChannel
  • Pipe.SinkChannel
  • Pipe.SourceChannel
  • SelectableChannel
  • ServerSocketChannel
  • SocketChannel

經常使用的有入下幾個:

  • FileChannel:用於讀取、寫入、映射和操做文件的通道。
  • DatagramChannel:經過 UDP 讀寫網絡中的數據通道。
  • SocketChannel:經過 TCP 讀寫網絡中的數據。
  • ServerSocketChannel:能夠監聽新進來的 TCP 鏈接,對每個新進來的鏈接都會建立一個 SocketChannel。

獲取通道

獲取通道的一種方式是對支持通道的對象調用getChannel() 方法。支持通道的類以下:

  • FileInputStream
  • FileOutputStream
  • RandomAccessFile
  • DatagramSocket
  • Socket
  • ServerSocket

獲取通道的其餘方式是使用 Files 類的靜態方法 newByteChannel() 獲取字節通道。或者經過通道的靜態方法 open() 打開並返回指定通道。

FileChannel

  • 爲了更形象解釋說明的Channel,下面準備以FileChannel的一些簡單代碼進行說明就容易懂了。
  • 準備以FileOutputStream類爲準,這兩個類都是支持通道操做的。
String info[] = {"歡迎","關注","匠心零度","的","公衆號","謝謝!!"} ;
File file = new File("d:" + File.separator + "testfilechannel.txt") ; 
FileOutputStream output = null ;
FileChannel fout = null;
try {
	output = new FileOutputStream(file) ;
	fout = null;
	fout = output.getChannel() ;	// 獲得輸出的通道
	ByteBuffer buf = ByteBuffer.allocate(1024) ; 
	for(int i=0;i<info.length;i++){
		buf.put(info[i].getBytes()) ;	// 字符串變爲字節數組放進緩衝區之中
	}
	buf.flip() ;
	fout.write(buf) ;	// 輸出緩衝區的內容
} catch (Exception e) {
	e.printStackTrace();
}finally{
	if(fout!=null){
		try {
			fout.close() ;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	if(output!=null){
		try {
			output.close() ;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
複製代碼

程序運行效果:

**說明:**今天只是NIO相關基礎篇一,因此有不少並無涉及到,但願上面說的這樣讓你們有一個新的瞭解,未完待續……

若是讀完以爲有收穫的話,歡迎點贊、關注、加公衆號【匠心零度】。


我的公衆號,歡迎關注,查閱更多精彩歷史!!!

匠心零度公衆號
相關文章
相關標籤/搜索