NIO 庫(kù)是在 JDK 1.4 中引入的。在Java1.4之前的I/O系統(tǒng)中,提供的都是面向流的I/O系統(tǒng),NIO 彌補(bǔ)了原來的 I/O 的不足,它在標(biāo)準(zhǔn) Java 代碼中提供了高速的、面向緩沖區(qū)的 I/O。通過定義包含數(shù)據(jù)的類,以及通過以塊的形式處理這些數(shù)據(jù),NIO 不用使用本機(jī)代碼就可以利用低級(jí)優(yōu)化,這是原來的 I/O 包所無(wú)法做到的。
java.NIO包里包括三個(gè)基本的組件:
1、buffer:因?yàn)镹IO是基于緩沖的,所以buffer是最底層的必要類,這也是IO和NIO的根本不同,雖然stream等有buffer開頭的擴(kuò)展類,但只是流的包裝類,還是從流讀到緩沖區(qū),而NIO卻是直接讀到buffer中進(jìn)行操作。因?yàn)樽x取的都是字節(jié),所以在操作文字時(shí),要用charset類進(jìn)行編解碼操作。
2、channel:類似于IO的stream,但是不同的是除了FileChannel,其他的channel都能以非阻塞狀態(tài)運(yùn)行。FileChannel執(zhí)行的是文件的操作,可以直接DMA操作內(nèi)存而不依賴于CPU。其他比如socketchannel就可以在數(shù)據(jù)準(zhǔn)備好時(shí)才進(jìn)行調(diào)用。
3、selector:用于分發(fā)請(qǐng)求到不同的channel,這樣才能確保channel不處于阻塞狀態(tài)就可以收發(fā)消息。
使用NIO實(shí)現(xiàn)讀寫:
在第一個(gè)練習(xí)中,將從一個(gè)文件中讀取一些數(shù)據(jù)。如果使用原來的 I/O,那么只需創(chuàng)建一個(gè) FileInputStream 并從它那里讀取。而在 NIO 中,情況稍有不同:我們首先從 FileInputStream 獲取一個(gè) Channel 對(duì)象,然后使用這個(gè)通道來讀取數(shù)據(jù)。在 NIO 系統(tǒng)中,任何時(shí)候執(zhí)行一個(gè)讀操作,都是從通道中讀取,但是不是 直接 從通道讀取。因?yàn)樗袛?shù)據(jù)最終都駐留在緩沖區(qū)中,所以是從通道讀到緩沖區(qū)中。因此讀取文件涉及三個(gè)步驟:從 FileInputStream 獲取 Channel、創(chuàng)建 Buffer、將數(shù)據(jù)從 Channel 讀到 Buffer 中。
(1) 第一步是獲取通道。從 FileInputStream 獲取通道:
FileInputStream fin = new FileInputStream( "E:/nio.txt" );
FileChannel fc = fin.getChannel();
(2) 下一步是創(chuàng)建緩沖區(qū)
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
(3) 最后,需要將數(shù)據(jù)從通道讀到緩沖區(qū)中,并輸出控制臺(tái)
fc.read( buffer );
buffer.flip();
while (buffer.hasRemaining()) {
// 讀取buffer當(dāng)前位置的整數(shù)
byte b = buffer.get();
System.out.print((char) b);
}
第二個(gè)練習(xí),寫入文件也包含三個(gè)步驟:從FileOutputStream獲取Channel、創(chuàng)建Buffer并且把數(shù)據(jù)放到Buffer中、將Buffer中的數(shù)據(jù)寫入Channel。
FileOutputStream fout = new FileOutputStream( "E:/nio.txt" );
FileChannel fc = fout.getChannel();
String str = "hello world!";
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
for (int i=0; i<str.length(); ++i) {
buffer.put( (byte) str.charAt(i) );
}
buffer.flip();
fc.write( buffer );
fout.close();