NIO的使用總結

背景

傳統流I/O是基於字節的,所有I/O都被視爲單個字節的移動;而NIO是基於塊的,大家可能猜到了,NIO的性能肯定優於流I/O。沒錯!其性能的提高 要得益於其使用的結構更接近操作系統執行I/O的方式:通道和緩衝器。
我們可以把它想象成一個煤礦,通道是一個包含煤層(數據)的礦藏,而緩衝器則是派送 到礦藏的卡車。卡車載滿煤炭而歸,我們再從卡車上獲得煤炭。也就是說,我們並沒有直接和通道交互;我們只是和緩衝器交互,並把緩衝器派送到通道。通道要麼 從緩衝器獲得數據,要麼向緩衝器發送數據。(這段比喻出自Java編程思想)
NIO的主要應用在高性能、高容量服務端應用程序,典型的有Apache Mina就是基於它的。

緩衝區Buffer
緩衝區實際上是一個容器對象,更直接的說,其實就是一個數組,在NIO庫中,所有數據都是用緩衝區處理的。在讀取數據時,它是直接讀到緩衝區中的; 在寫入數據時,它也是寫入到緩衝區中的;任何時候訪問 NIO 中的數據,都是將它放到緩衝區中。而在面向流I/O系統中,所有數據都是直接寫入或者直接將數據讀取到Stream對象中。
在NIO中,所有的緩衝區類型都繼承於抽象類Buffer,最常用的就是ByteBuffer,對於Java中的基本類型,基本都有一個具體Buffer類型與之相對應,它們之間的繼承關係如下圖所示:
下面是一個簡單的使用IntBuffer的例子:
public class TestIntBuffer {  
    public static void main(String[] args) {  
        // 分配新的int緩衝區,參數爲緩衝區容量  
        // 新緩衝區的當前位置將爲零,其界限(限制位置)將爲其容量。它將具有一個底層實現數組,其數組偏移量將爲零。  
        IntBuffer buffer = IntBuffer.allocate(8);  
  
        for (int i = 0; i < buffer.capacity(); ++i) {  
            int j = 2 * (i + 1);  
            // 將給定整數寫入此緩衝區的當前位置,當前位置遞增  
            buffer.put(j);  
        }  
  
        // 重設此緩衝區,將限制設置爲當前位置,然後將當前位置設置爲0  
        buffer.flip();  
  
        // 查看在當前位置和限制位置之間是否有元素  
        while (buffer.hasRemaining()) {  
            // 讀取此緩衝區當前位置的整數,然後當前位置遞增  
            int j = buffer.get();  
            System.out.print(j + "  ");  
        }  
  
    }  
  
}  

通道Channel
通道是一個對象,通過它可以讀取和寫入數據,當然了所有數據都通過Buffer對象來處理。我們永遠不會將字節直接寫入通道中,相反是將數據寫入包含一個或者多個字節的緩衝區。同樣不會直接從通道中讀取字節,而是將數據從通道讀入緩衝區,再從緩衝區獲取這個字節。
在NIO中,提供了多種通道對象,而所有的通道對象都實現了Channel接口。它們之間的繼承關係如下圖所示:

使用NIO讀取數據

在前面我們說過,任何時候讀取數據,都不是直接從通道讀取,而是從通道讀取到緩衝區。所以使用NIO讀取數據可以分爲下面三個步驟: 
1. 從FileInputStream獲取Channel 
2. 創建Buffer 
3. 將數據從Channel讀取到Buffer中
下面是一個簡單的使用NIO從文件中讀取數據的例子:
public class Program {  
    static public void main( String args[] ) throws Exception {  
        FileInputStream fin = new FileInputStream("c:\\test.txt");  
          
        // 獲取通道  
        FileChannel fc = fin.getChannel();  
          
        // 創建緩衝區  
        ByteBuffer buffer = ByteBuffer.allocate(1024);  
          
        // 讀取數據到緩衝區  
        fc.read(buffer);  
          
        buffer.flip();  
          
        while (buffer.remaining()>0) {  
            byte b = buffer.get();  
            System.out.print(((char)b));  
        }  
          
        fin.close();  
    }  
}
使用NIO寫入數據
使用NIO寫入數據與讀取數據的過程類似,同樣數據不是直接寫入通道,而是寫入緩衝區,可以分爲下面三個步驟: 
1. 從FileInputStream獲取Channel 
2. 創建Buffer 
3. 將數據從Channel寫入到Buffer中
下面是一個簡單的使用NIO向文件中寫入數據的例子:
public class Program {  
    static private final byte message[] = { 83, 111, 109, 101, 32,  
        98, 121, 116, 101, 115, 46 };  
  
    static public void main( String args[] ) throws Exception {  
        FileOutputStream fout = new FileOutputStream( "c:\\test.txt" );  
          
        FileChannel fc = fout.getChannel();  
          
        ByteBuffer buffer = ByteBuffer.allocate( 1024 );  
          
        for (int i=0; i<message.length; ++i) {  
            buffer.put( message[i] );  
        }  
          
        buffer.flip();  
          
        fc.write( buffer );  
          
        fout.close();  
    }  
}  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章