日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java nio剖析

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

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{
        
//分配一個非直接緩沖區(qū)
        ByteBuffer bb = ByteBuffer.allocate(100);
        
//向緩沖區(qū)寫入0到100的字節(jié)制
        for(int i = 0; i <100; i++){
            
byte b = (byte) (Math.random() * 100);
            bb.put(b);
        }

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

    }


}

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

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{
        
        
//將文件內(nèi)容讀到緩沖區(qū)中
        FileChannel fc = new FileInputStream("buffer.txt").getChannel();
        ByteBuffer bb 
= ByteBuffer.allocate((int) fc.size());
        fc.read(bb);
        fc.close();
        fc 
= null;
        
        System.out.println(
"從文件讀取的字節(jié)緩沖區(qū)數(shù)據(jù)");
        bb.flip();
        
while(bb.hasRemaining())
            System.out.print(bb.get() 
+ " ");
        System.out.println();
        
        
//獲取視圖緩沖區(qū)
        bb.flip();
        IntBuffer ib 
= bb.asIntBuffer();
        System.out.println(
"將字節(jié)緩沖區(qū)作為整形緩沖區(qū)的數(shù)據(jù)");
        
while(ib.hasRemaining())
            System.out.print(ib.get() 
+ " ");
        System.out.println();
        
        bb 
= null;
        ib 
= null;
        
    }


}

       4.映射內(nèi)存緩沖區(qū)
         調(diào)用信道的map()方法后,即可將文件的某一部分或全部映射到內(nèi)存中,映射內(nèi)存緩沖區(qū)是一
         個直接緩沖區(qū),繼承自ByteBuffer,但相對于ByteBuffer,它有更多的優(yōu)點:
a.     內(nèi)存映射I/O是對信道/緩沖區(qū)技術(shù)的改進。 當傳輸大量的數(shù)據(jù)時,內(nèi)存映射I/O
速度相對較快,這是因為它使用虛擬內(nèi)存把文件傳輸?shù)竭M程的地址空間中。
b.      映射內(nèi)存也成為共享內(nèi)存,因此可以用于相關(guān)進程(均映射同一文件)之間的整塊數(shù)據(jù)
傳輸,這些進程甚至可以不必位于同一系統(tǒng)上,只要每個都可以訪問同一文件即可。
c.       當對FileChannel執(zhí)行映射操作,把文件映射到內(nèi)存中時,得到的是一個連接到文件的
映射的字節(jié)緩沖區(qū),這種映射的結(jié)果是,當輸出緩沖區(qū)的內(nèi)容時,數(shù)據(jù)將出現(xiàn)在文件中,
當讀入緩沖區(qū)時,相當于得到文件中的數(shù)據(jù)。
        下面這個例子演示了映射內(nèi)存:
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;

    }


}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多