1. 程式人生 > >Java NIO學習

Java NIO學習

Java的普通IO是面向流的IO,從流中讀取資料,將資料寫入流中。是一個位元組一個位元組的讀取和寫入,而NIO是jdk1.4後推出的面向塊的IO流,通過加入緩衝區和管道,以資料塊為單位對資料進行IO。

緩衝區Buffer:

本質是一個由陣列實現的容器,資料從檔案或從其他地方讀取首先需要裝入到緩衝區中,寫入也是先寫入到緩衝區,而不是直接從Stream中讀取或寫入。

管道Channel:

資料傳輸的通道,從緩衝區裡讀取資料然後進行傳輸,從管道中讀取資料也是先將資料寫入到緩衝區中。管道是雙向的,可讀可寫。

傳輸過程:

讀:檔案———Channel———Buffer

寫:Buffer———Channel———檔案

程式碼演示:

讀:

    //讀NIO
    public static void readNIO() throws Exception {
        FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
        //獲取管道
        FileChannel fileChannel = fileInputStream.getChannel();
        //建立位元組緩衝區,容量為1024位元組
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //從管道里讀資料裝入緩衝區
        fileChannel.read(byteBuffer);
        // 重設buffer,將limit設定為讀取到的當前位置position,position設定為0,即開始位置。
        byteBuffer.flip();
        //檢視在position和limit之間是否有元素
        while (byteBuffer.hasRemaining()){
            //獲取當前位置的一個位元組
            byte b = byteBuffer.get();
            System.out.println((char)b);
        }
        fileInputStream.close();

    }

寫:

public static void writeNIO() throws Exception {
        byte message[] = { 'h', 'e', 'l', 'l','o', ' ','w', 'o','r', 'l','d', '!' };
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");
        FileChannel fileChannel = fileOutputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //重設buffer,將limit設定為capacity,position設定為0,即開始位置。可重新寫入資料
        byteBuffer.clear();
        //寫入到緩衝區
        for (int i = 0; i < message.length; i++) {
            byteBuffer.put(message[i]);
        }
        byteBuffer.flip();
        //從緩衝區寫入到管道
        fileChannel.write(byteBuffer);
        fileOutputStream.close();
    }

讀寫:

//讀寫NIO
    public static void readandwriteNIO() throws Exception {
        FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
        //獲取管道
        FileChannel fileChannel = fileInputStream.getChannel();
        //建立位元組緩衝區,容量為1024位元組
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //從管道里讀資料裝入緩衝區
        fileChannel.read(byteBuffer);
        // 獲取輸出channel
        FileOutputStream fileOutputStream = new FileOutputStream("D:\\test2.txt");
        FileChannel fileChannel2 = fileOutputStream.getChannel();
        //將position和limit重置
        byteBuffer.clear();
        fileChannel2.write(byteBuffer);
        fileInputStream.close();
        fileOutputStream.close();
    }

讀和寫過程並沒有告訴管道需要讀寫多少資料,因為buffer中自帶計數的東西。

position:資料讀取的下一個位置,比如現在已經讀到了第三個,那麼position就指向第四個。

limit:資料還剩多少沒讀,或者還有多少空間可以寫。

capacity:buffer的總的容量。

position總是小於等於limit。limit總是小於等於capacity。

當然,NIO不止這些,IO是一個執行緒服務於一個流,而NIO一個執行緒可以服務於多個流,將多個流注冊到一個Selector上,Selector會對這些流進行監聽,當某個流有讀寫事件時,會對其進行處理。一個執行緒不必停留在一個流上,可以處理其他流,所以說NIO是非阻塞的。

NIO是同步的,因為始終有一個執行緒服務於這些流,這個執行緒並沒有去做其他工作。真正的非同步是作業系統負責把資料拷貝到使用者空間,然後通知這個執行緒,這裡的訊息通知機制就是非同步。而NIO是自己啟一個執行緒去監控stream裡面有沒有資料。

同步和非同步說的是訊息的通知機制,阻塞非阻塞說的是執行緒的狀態 。同步非同步關注點是你問核心資料有沒有準備好,還是核心主動通知你資料有沒有準備好。阻塞非阻塞關注點是你的處理執行緒在資料沒有準備好的時候是一直在等待狀態還是可以去做其他的事情。

引用別人的同步非同步,阻塞非阻塞的生動解釋:

1 老張把水壺放到火上,原地不動等水開。(同步阻塞)                                   

 ---------->老張覺得自己有點傻

2 老張把水壺放到火上,去客廳看毛騙,時不時去看看水開沒有。(同步非阻塞) 

 ---------->老張覺得自己有點傻

於是變高端了,買了把會響笛的那種水壺。水開之後,能大聲發出嘀~~~~的響聲。

3 老張把響水壺放到火上,立等水開。(非同步阻塞)                                                

 --------->老張覺得自己有點傻

4 老張把響水壺放到火上,去客廳看毛騙,水壺響之前不再去看它,響了再去拿壺。(非同步非阻塞) 

---------->嗯,老張覺得自己棒棒噠

Selector :是NIO中最關鍵的一個部分,Selector的作用就是用來輪詢每個註冊的Channel,一旦發現Channel有註冊的事件發生,便獲取事件然後進行處理。