Java NIO2:NIO概述

來源:互聯網
上載者:User

標籤:input   leo   限制   sage   9.png   發送   分享   映射   ntb   

一、概述

     從JDK1.4開始,Java提供了一系列改進的輸入/輸出處理的新特性,被統稱為NIO(即New I/O)。新增了許多用於處理輸入輸出的類,這些類都被放在java.nio包及子包下,並且對原java.io包中的很多類進行改寫,新增了滿足NIO的功能。NIO採用記憶體對應檔的方式來處理輸入輸出,NIO將檔案或檔案的一段區域對應到記憶體中,這樣就可以像訪問記憶體一樣訪問檔案了。

NIO 與原來的 I/O 有同樣的作用和目的,但是它使用不同的方式?  塊I/O。塊 I/O 的效率可以比流 I/O 高許多。

流與塊的比較

     原來的 I/O 庫(在 java.io.*中) 與 NIO 最重要的區別是資料打包和傳輸的方式。正如前面提到的,原來的 I/O 以流的方式處理資料,而 NIO 以塊的方式處理資料。

     面向流 的 I/O 系統一次一個位元組地處理資料。一個輸入資料流產生一個位元組的資料,一個輸出資料流消費一個位元組的資料。為流式資料建立過濾器非常容易。連結幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。

     一個 面向塊 的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個資料區塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。

     在NIO中有幾個核心對象需要掌握:緩衝區(Buffer)、通道(Channel)、選取器(Selector)。

二、緩衝區Buffer

     緩衝區實際上是一個容器物件,更直接的說,其實就是一個數組,在NIO庫中,所有資料都是用緩衝區處理的。在讀取資料時,它是直接讀到緩衝區中的; 在寫入資料時,它也是寫入到緩衝區中的;任何時候訪問 NIO 中的資料,都是將它放到緩衝區中。而在面向流I/O系統中,所有資料都是直接寫入或者直接將資料讀取到Stream對象中。具體看下面這張圖就理解了:

    上面的圖描述了從一個用戶端向服務端發送資料,然後服務端接收資料的過程。用戶端發送資料時,必須先將資料存入Buffer中,然後將Buffer中的內容寫入通道。服務端這邊接收資料必須通過Channel將資料讀入到Buffer中,然後再從Buffer中取出資料來處理。

    在NIO中,所有的緩衝區類型都繼承於抽象類別Buffer,最常用的就是ByteBuffer,對於Java中的基本類型,基本都有一個具體Buffer類型與之相對應,它們之間的繼承關係如所示:

下面是一個簡單使用IntBuffer的例子:

package com.demo.nio;import java.nio.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

      Channel和傳統IO中的Stream很相似。雖然很相似,但是有很大的區別,主要區別為:通道是雙向的,通過一個Channel既可以進行讀,也可以進行寫;而Stream只能進行單向操作,通過一個Stream只能進行讀或者寫,比如InputStream只能進行讀取操作,OutputStream只能進行寫操作;

      通道是一個對象,通過它可以讀取和寫入資料,當然了所有資料都通過Buffer對象來處理。我們永遠不會將位元組直接寫入通道中,相反是將資料寫入包含一個或者多個位元組的緩衝區。同樣不會直接從通道中讀取位元組,而是將資料從通道讀入緩衝區,再從緩衝區擷取這個位元組。

      在NIO中,提供了多種通道對象,而所有的通道對象都實現了Channel介面。它們之間的繼承關係如所示:

 

    Channel(通道)表示到實體如硬體裝置、檔案、網路通訊端或可以執行一個或多個不同I/O操作的程式組件的開放的串連。所有的Channel都不是通過構造器建立的,而是通過傳統的節點InputStream、OutputStream的getChannel方法來返迴響應的Channel。

  Channel中最常用的三個類方法就是map、read和write,其中map方法用於將Channel對應的部分或全部資料對應成ByteBuffer,而read或write方法有一系列的重載形式,這些方法用於從Buffer中讀取資料或向Buffer中寫入資料。

1、使用NIO讀取資料

在前面我們說過,任何時候讀取資料,都不是直接從通道讀取,而是從通道讀取到緩衝區。所以使用NIO讀取資料可以分為下面三個步驟: 
(1). 從FileInputStream擷取Channel 
(2). 建立Buffer 
(3). 將資料從Channel讀取到Buffer中

下面是一個簡單的使用NIO從檔案中讀取資料的例子:

import java.io.*;  import java.nio.*;  import java.nio.channels.*;    public class Program {      public static 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();      }  }  

2、使用NIO寫入資料

使用NIO寫入資料與讀取資料的過程類似,同樣資料不是直接寫入通道,而是寫入緩衝區,可以分為下面三個步驟:
(1). 從FileInputStream擷取Channel
(2). 建立Buffer
(3). 將資料從Channel寫入到Buffer中

下面是一個簡單的使用NIO向檔案中寫入資料的例子:

package com.demo.nio;import java.io.FileOutputStream;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;public class Program {        private static final byte message[] = { 83, 111, 109, 101, 32,        98, 121, 116, 101, 115, 46 };    public static 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();    }}

四、選取器Selector

      Selector類是NIO的核心類,Selector能夠檢測多個註冊的通道上是否有事件發生,如果有事件發生,便擷取事件然後針對每個事件進行相應的響應處理。這樣一來,只是用一個單線程就可以管理多個通道,也就是管理多個串連。這樣使得只有在串連真正有讀寫事件發生時,才會調用函數來進行讀寫,就大大地減少了系統開銷,並且不必為每個串連都建立一個線程,不用去維護多個線程,並且避免了多線程之間的環境切換導致的開銷。

  與Selector有關的一個關鍵類是SelectionKey,一個SelectionKey表示一個到達的事件,這2個類構成了服務端處理業務的關鍵邏輯。

Java NIO2:NIO概述

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.