posts - 41,  comments - 8,  trackbacks - 0
          java nio的全稱是java new I/O,即一個全新的I/O控制系統,它的API的包名為java.nio,是在jdk1.4后引入的。
          nio之所以為為新,在于它并沒在原來I/O的基礎上進行開發,而是提供了全新的類和接口,除了原來的基本功能之外,它還提供了以下新的特征:
                  ? 多路選擇的非封鎖式I/O設施
                  ?支持文件鎖和內存映射
                  ?支持基于Perl風格正則表達式的模式匹配設施
                  ?字符集編碼器和譯碼器
                  為了支持這些新的功能,nio使用了兩個新的概念:
                    1. 信道(channel)
                        信道是一個連接,可用于接收或發送數據,如文件和套接字。因為信道連接的是底層的物理設備,他可以直接支持設備的讀/寫,或提供文件鎖。對于文件、管道、套接字都存在相應的信道類。可以把信道看成是數據流的替代品。信道沒有包裝類,提高了性能。
                       所有的信道類都位于java.nio.channels包中。
                   2. 緩沖區(buffer)
                        緩沖區是一個數據容器。可以把它看做內存中的一個大的數組,用來存儲來自信道的同一類型的所有數據,因此,程序員可以使用字節、字符、整數等緩沖區。字節緩沖區提供必要的方法,可以提取或存入所有基本類型(boolean型除外)的數據。 
                        buffer類的核心是一塊內存區,便于核心代碼和java代碼同時訪問,核心代碼可以直接訪問它,java代碼可以通過API訪問它。
                       緩沖區基本上是一塊內存區域,因而可以執行一些與內存有關的操作,如清除其中的內容,支持讀寫或只讀操作等。
                       所有的buffer類都位于java.nio包中。
                 下面看如何使用它們:
          1.      使用信道
          在信道的使用中,文件的信道是最具有代表性的,API也是最多的,下面我們以文件信道為例介紹它。
               獲取文件信道
          文件的信道的類為FileChannel,遺憾的是他并沒有向我們提供打開文件的方法,我們可以通過調用FileInputStream、FileOutputStream和RandomAccessFile類實例的getChannel()方法來獲取其實例。例如:
          RandomAccessFile raf = new RandomAccessFile(“data.txt”, “rw”);
          FileChannel fc = raf.getChannel();
          請注意,這里打開文件的方式如”rw”將適用于文件信道,FileInputStream實例的getChannel()方法所獲得的通道將允許進行讀取操作。通過FileOutputStream的getChannel方法所獲得的通道將允許進行寫入操作。最后,如果使用模式 "r" 創建 RandomAccessFil的實例,則通過該實例的getChannel()方法所獲得的通道將允許進行讀取操作,如果使用模式 "rw" 創建實例,則獲得的通道將允許進行讀取和寫入操作。
              從信道讀取數據
          讀取的數據會默認放到字節緩沖區中。
          FileChannel提供了四個API讀取數據:
          a.    read(ByteBuffer dst) 將字節序列從此通道讀入給定的緩沖區
          b.   read(ByteBuffer[] dsts) 將字節序列從此通道讀入給定的緩沖區
          c.    read(ByteBuffer[] dsts, int offset, int length)
                    將字節序列從此通道讀入給定緩沖區的子序列中
          d.    read(ByteBuffer dst, long position)
                    從給定的文件位置開始,從此通道讀取字節序列,并寫入給定的緩沖區
              向信道寫入數據
          數據來源默認是字節緩沖區。
          FileChannel提供了四個API寫入數據:
          a. write(ByteBuffer src)
                    將字節序列從給定的緩沖區寫入此通道
          b. write(ByteBuffer[] srcs)
                    將字節序列從給定的緩沖區寫入此通道
          c. write(ByteBuffer[] srcs, int offset, int length)
                    將字節序列從給定緩沖區的子序列寫入此通道
          d. write(ByteBuffer src, long position)
                    從給定的文件位置開始,將字節序列從給定緩沖區寫入此通道
                      ● 使用文件鎖
                         文件鎖機制主要是在多線程同時讀寫某個文件資源時使用。
                         FileChannel提供了兩種加鎖機制,lock和tryLock,兩者的區別在于,lock是同步的,
                         直至成功才返回,tryLock是異步的,無論成不成功都會立即返回。
                      ● 使用內存映射
                           FileChannel提供的的API為:
                           MappedByteBuffer map(FileChannel.MapMode mode,  long position, long size);
                                映射模式一個有三種:
                                a.只讀: 試圖修改得到的緩沖區將導致拋出 ReadOnlyBufferException.(MapMode.READ_ONLY)
                    b.讀/寫 對得到的緩沖區的更改最終將傳播到文件;該更改對映射到同一文件的其他程序不一定是可見的。 (MapMode.READ_WRITE)
                                c.專用 對得到的緩沖區的更改不會傳播到文件,并且該更改對映射到同一文件的其他程序也不是可見的;相反,會創建緩沖區已修改部分的專用副本。 (MapMode.PRIVATE)
          2.      使用緩沖區
               層次結構
          所有緩沖區的基類都是Buffer,Boolean類型外,其它數據類型都有對應的緩沖區類,
          另有一個ByteOrder類,用來設置緩沖區的大小端順序,即BigEndian或者是LittleEndian
          默認情況下是BigEndian。其層次結構圖如下:
               獲取緩沖區對象
          一共有兩種類型的緩沖區,直接緩沖區和非直接緩沖區,兩者區別在于直接緩沖區上的數據操作,
          虛擬機將盡量使用本機I/O,并盡量避免使用中間緩沖區。判斷一個緩沖區是否是直接緩沖區,
          可以調用isDirect()方法。
          有三種方式來獲取一個緩沖區的對象:
          a.      調用allocate()或者allocateDirect()方法直接分配,其中allocateDirect()
          返回的是直接緩沖區。
          b.      包裝一個數組,如:
          byte[] b = new byte[1024];
          ByteBuffer bb = ByteBuffer.wrap(b);
          c.       內存映射,即調用FileChannelmap()方法。
               緩沖區基本屬性
          這幾個屬性是每個緩沖區都有的并且是常用的操作。
          a.     容量(capacity),緩沖區大小
          b.      限制(limit),第一個不應被讀取或寫入的字節的索引,總是小于容量。
          c.       位置(position),下一個被讀取或寫入的字節的索引,總是小于限制。
          d.      clear()方法:設置limit為capacity,position為0。
          e.      filp()方法:設置limit為當前position,然后設置position為0。
          f.        rewind()方法:保持limit不變,設置position為0。
               緩沖區數據操作
          操作包括了讀取和寫入數據兩種。
          讀取數據使用get()及其系列方法,除boolean外,每一種類型包括了對應的get()方法,
          如getInt(),getChar()等,get()方法用來讀取字節,支持相對和絕對索引兩種方式。
          寫入數據使用put()及其系列方法,和get()方法是對應的。
                     下面這個例子演示了如何使用緩沖區和信道:
          
          
          package nio;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.nio.ByteBuffer;
          import java.nio.channels.FileChannel;

          public class BufferDemo {

              
              
          public static void main(String[] args) throws Exception{
                  
          //分配一個非直接緩沖區
                  ByteBuffer bb = ByteBuffer.allocate(100);
                  
          //向緩沖區寫入0到100的字節制
                  for(int i = 0; i <100; i++){
                      
          byte b = (byte) (Math.random() * 100);
                      bb.put(b);
                  }

                  
                  System.out.println(
          "寫入文件前的緩沖區數據");
                  bb.flip();
                  
          while(bb.hasRemaining())
                      System.out.print(bb.get() 
          + " ");
                  System.out.println();
                  
                  
          //獲取一個關聯到文件buffer.txt的信道
                  FileChannel fc = new FileOutputStream("buffer.txt").getChannel();
                  
          //將緩沖區數據寫到文件中
                  bb.flip();
                  fc.write(bb);
                  
          //防止緩存
                  fc.force(true);
                  
          //關閉信道
                  fc.close();
                  bb 
          = null;
                  fc 
          = null;
                  
                  
          //下面從文件中讀取數據
                  fc = new FileInputStream("buffer.txt").getChannel();
                  ByteBuffer bb2 
          = ByteBuffer.allocate((int) fc.size());
                  fc.read(bb2);
                  System.out.println(
          "從文件讀取的緩沖區數據");
                  bb2.flip();
                  
          while(bb2.hasRemaining())
                      System.out.print(bb2.get() 
          + " ");
                  System.out.println();
                  fc.close();
                  bb2 
          = null;
                  fc 
          = null;
                  

              }


          }

                   3.視圖緩沖區
                   上面我們的緩沖區都是基于字節的,像IntBuffer、LongBuffer等這些都可以調用ByteBuffer的
                   as***Buffer(***表示某個數據類型)得到,所以這種類型的緩沖區又被稱為視圖緩沖區(View Buffer),
                 視圖緩沖區有以下特點:
          a.     視圖緩沖區有自己獨立的position和limit,但它不是一個新的創建,只是原來字節緩沖區的一個邏輯緩沖區,字節緩沖區的任何修改都會影響視圖緩沖區,反之亦然。
          b.      視圖緩沖區按照數據類型的大小進行索引,而不是字節順序。
          c.       也提供了put()和get()及其系列方法,用于數據的整塊傳輸。
                 下面這個例子演示了視圖緩沖區:
          
          
          package nio;

          import java.io.FileInputStream;
          import java.nio.ByteBuffer;
          import java.nio.IntBuffer;
          import java.nio.channels.FileChannel;

          public class ViewBufferDemo {

              
          public static void main(String[] args) throws Exception{
                  
                  
          //將文件內容讀到緩沖區中
                  FileChannel fc = new FileInputStream("buffer.txt").getChannel();
                  ByteBuffer bb 
          = ByteBuffer.allocate((int) fc.size());
                  fc.read(bb);
                  fc.close();
                  fc 
          = null;
                  
                  System.out.println(
          "從文件讀取的字節緩沖區數據");
                  bb.flip();
                  
          while(bb.hasRemaining())
                      System.out.print(bb.get() 
          + " ");
                  System.out.println();
                  
                  
          //獲取視圖緩沖區
                  bb.flip();
                  IntBuffer ib 
          = bb.asIntBuffer();
                  System.out.println(
          "將字節緩沖區作為整形緩沖區的數據");
                  
          while(ib.hasRemaining())
                      System.out.print(ib.get() 
          + " ");
                  System.out.println();
                  
                  bb 
          = null;
                  ib 
          = null;
                  
              }


          }

                 4.映射內存緩沖區
                   調用信道的map()方法后,即可將文件的某一部分或全部映射到內存中,映射內存緩沖區是一
                   個直接緩沖區,繼承自ByteBuffer,但相對于ByteBuffer,它有更多的優點:
          a.     內存映射I/O是對信道/緩沖區技術的改進。 當傳輸大量的數據時,內存映射I/O
          速度相對較快,這是因為它使用虛擬內存把文件傳輸到進程的地址空間中。
          b.      映射內存也成為共享內存,因此可以用于相關進程(均映射同一文件)之間的整塊數據
          傳輸,這些進程甚至可以不必位于同一系統上,只要每個都可以訪問同一文件即可。
          c.       當對FileChannel執行映射操作,把文件映射到內存中時,得到的是一個連接到文件的
          映射的字節緩沖區,這種映射的結果是,當輸出緩沖區的內容時,數據將出現在文件中,
          當讀入緩沖區時,相當于得到文件中的數據。
                  下面這個例子演示了映射內存:
          package nio;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.nio.MappedByteBuffer;
          import java.nio.channels.FileChannel;

          public class CopyFile {

              
          public static void main(String[] args) throws Exception {

                  FileChannel fIChan, fOChan;
                  MappedByteBuffer mBuf;

                  fIChan 
          = new FileInputStream("buffer.txt").getChannel();
                  fOChan 
          = new FileOutputStream("bufferTemp.txt").getChannel();

                  mBuf 
          = fIChan.map(FileChannel.MapMode.READ_ONLY, 0, fIChan.size());

                  fOChan.write(mBuf);

                  fIChan.close();
                  fOChan.close();
                  
                  fIChan 
          = null;
                  fOChan 
          = null;
                  mBuf 
          = null;

              }


          }

          posted on 2008-10-21 17:44 Loy Fu 閱讀(839) 評論(0)  編輯  收藏 所屬分類: java
          主站蜘蛛池模板: 高青县| 乌苏市| 郁南县| 洛宁县| 三门县| 唐河县| 宿松县| 北海市| 浏阳市| 泽普县| 涟源市| 普安县| 和政县| 衡阳市| 金沙县| 镇宁| 南郑县| 徐汇区| 虞城县| 闽清县| 从化市| 绥芬河市| 南漳县| 南丰县| 鄢陵县| 凤翔县| 璧山县| 安国市| 涟源市| 固镇县| 康平县| 新巴尔虎左旗| 泰安市| 岫岩| 冷水江市| 烟台市| 旬阳县| 巨野县| 青冈县| 婺源县| 云南省|