1. 程式人生 > >Java-NIO學習小結

Java-NIO學習小結

一、Java NIO概述

  1. Java NIO由如下三個核心部分組成:
    • Channels 管道;負責連線TCP、UDP、File等進行資料的讀寫;管道每次讀寫資料都需要經過Buffers
    • Buffers 緩衝區;負責接收管道讀取的資料/向管道傳輸資料;
    • Selectors 選擇器;負責註冊的管道,並監聽管道的資料流動;呼叫select方法,會阻塞到管道中事件發生,返回後可以對這個事件進行處理

Selector和Channels的關係

二、Channel

  1. Java NIO的Channel與流類似,區別:流的讀寫是單向的,而管道的是雙工的,既可讀又可寫,不過在讀寫切換之前需要呼叫channel.flip()方法進行讀寫模式的切換。
    而且 管道可以非同步的讀寫。

  2. Channel的重要實現:

    • FileChannel:檔案讀寫
    • DatagramChannle:UDP網路讀寫
    • SocketChannel:TCP網路讀寫
    • ServerSocketChannel:可以向Web伺服器一樣監聽新進來的TCP連線,然後對於每個連線建立響應的SocketChannel讀取其中的資料=

    Channel通過Buffer進行資料讀寫的程式碼示例:

    
    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");//定義一個檔案
    FileChannel inChannel = aFile.getChannel();//獲取檔案的管道
    ByteBuffer buf = ByteBuffer.allocate(48);//建立一個每次可以讀寫48個位元組的緩衝區 int bytesRead = inChannel.read(buf); //管道讀取資料到緩衝區,每次讀滿48個位元組介紹並返回讀取的位元組個數 while (bytesRead != -1) { //當資料讀取完以後返回-1 System.out.println("Read " + bytesRead); buf.flip();//反轉緩衝區,從寫入模式切換到讀取模式 while(buf.hasRemaining()){//讀取緩衝區裡的資料
    System.out.print((char) buf.get()); } buf.clear();//緩衝區的資料滿後,要clear()/compact()才能繼續寫入資料 bytesRead = inChannel.read(buf); } aFile.close();
  3. Buffer 本質上是一塊兒可以寫入資料,又可以從中讀取資料的記憶體,被包裝成了NIO Buffer物件,並提供了一組方法來訪問該塊記憶體。
    • capacity:緩衝區的容量
    • position:位置指示器,初始值都為零。寫模式時,從零移動到capacity-1(或limit,即可用空間的限制)的地方,每寫入一個值就會,position都會移動到下一個可寫入位置的序號;從寫模式切換到讀模式時,position置零,然後開始移動,直到到上次寫入的最後序號limit(即切換時,limit=position)
    • limit:可讀/寫的限制
  4. Buffer的實現類

    • ByteBuffer
    • MappedByteBuffer
    • CharBuffer
    • DoubleBufferoatBuffer
    • IntBuffer
    • LongBuffer
    • ShortBuffer
  5. 常用方法

    • allocate(int capacity):初始化一個緩衝區,指定其大小
    • put()

三、Scatter和Gather

分散(scatter)從Channel中讀取是指在讀操作時將讀取的資料寫入多個buffer中。因此,Channel將從Channel中讀取的資料“分散(scatter)”到多個Buffer中。

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);

ByteBuffer[] bufferArray = { header, body };

channel.read(bufferArray);

聚集(gather)寫入Channel是指在寫操作時將多個buffer的資料寫入同一個Channel,因此,Channel 將多個Buffer中的資料“聚集(gather)”後傳送到Channel。

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);

//write data into buffers

ByteBuffer[] bufferArray = { header, body };

channel.write(bufferArray);

注意buffer首先被插入到陣列,然後再將陣列作為channel.read() 的輸入引數。read()方法按照buffer在陣列中的順序將從channel中讀取的資料寫入到buffer,當一個buffer被寫滿後,channel緊接著向另一個buffer中寫。所以如果需要指定資料到指定的Channel中,必須使用資料的長度來定義相應Channel的容積

四、Selector 選擇器