[Java]nio(一)——綜述__nio

來源:互聯網
上載者:User

背景 組成部分 通道和緩衝器 讀寫執行個體

背景

  JDK1.4的java.nio.*包中引入了新的JavaI/O類庫,其目的在於 提高速度。實際上,舊的I/O包已經使用nio重新實現過。因此,即使不顯式使用nio編寫代碼,也能從中受益。
  I/O的應用情境分為檔案I/O和網路I/O,在這裡之研究前者。 組成部分

  nio主要有三大組成部分:通道(Channel)、緩衝器(Buffer)、Selector(選擇區)。
  因為nio的資料轉送結構更接近於作業系統執行I/O的方式:通道緩衝器,而傳統的I/O是面向位元組流和字元流,所以nio的速度更快。
  通道用於存放資料,緩衝器用於傳輸資料,選擇區用於監聽多個通道的事件(比如:串連開啟,資料到達)。 通道和緩衝器

  我們並沒有直接和通道互動,我們只是和緩衝器互動,並把緩衝器派送到通道。通道要麼從緩衝器獲得資料,要麼向緩衝器發送資料。
  唯一直接與通道互動的緩衝器是ByteBuffer,即可以儲存未加工位元組的緩衝器。它是一個很基礎的類:通過告知分配多少儲存空間來建立一個ByteBuffer對象,並且還有一個選擇集。用於以原始的位元組形式或基礎資料型別 (Elementary Data Type)輸出和讀取資料。但是它不能直接讀取或輸出對象,即使是字串對象也不行。雖然這種處理很低級,但是卻更貼合作業系統的處理方式。
  舊I/O類庫中的FileInputStream、FileOutputStream、RandomAccessFile這三個類被修改了,用以產生FileChannel。這三個類都是位元組操縱流,與nio性質一致。像Reader和Writer這種面向字元流的類就不能用於產生通道;但是java.nio.channels.Channels類中提供了方法,可以在通道中產生Reader和Writer。 讀寫執行個體

public class GetChannel {    private static final int BSIZE = 2014;    public static void main(String[] args) throws IOException {        /**         * 寫資料,         * 若已有內容,原內容會被覆蓋;         * 若不存在檔案,則會建立新檔案並寫入新內容         */        FileChannel fc = new FileOutputStream("data.txt").getChannel();        fc.write(ByteBuffer.wrap("some text".getBytes()));        fc.close();        /**         * 新增內容至檔案末尾         */        fc = new RandomAccessFile("data.txt", "rw").getChannel();        fc.position(fc.size());     // 移動到檔案末尾        fc.write(ByteBuffer.wrap("Some more".getBytes()));        fc.close();        /**         * 讀取檔案         */        fc = new FileInputStream("data.txt").getChannel();        ByteBuffer buff = ByteBuffer.allocate(BSIZE);        fc.read(buff);        buff.flip();        while(buff.hasRemaining()){            System.out.print((char)buff.get());        }    }}
channel:對於上述三種流類,getChannel()方法都可以獲得一個FileChannel。通道是一種相當基礎的東西:可以向它 傳送用於讀寫的ByteBuffer,並且可以鎖定檔案的某些地區用於獨佔式訪問 ByteBuffer:將位元組存放於ByteBuffer的方法之一是:使用一種 “put”方法直接對它們進行填充,填入一個或多個位元組,或基礎資料型別 (Elementary Data Type)的值。也可以 使用wrap()方法將已存在的位元組數組“封裝”到ByteBuffer中,這樣就把一個數組封裝為ByteBuffer緩衝器,一旦完成封裝,底層資料就可以通過緩衝區或者直接存取。我們稱第二種為 數組支援的ByteBuffer position:可以使用FileChannel的position方法來在檔案中移動FileChannel。在上例中是將其移動到檔案末尾,方便內容的增加。 allocate:對於唯讀訪問,我們要顯式使用靜態allocate()方法來分配ByteBuffer,nio的目標就是快速移動大量資料,因此ByteBuffer的大小就顯得尤為重要——事實上,這裡使用的1K可能比我們通常要使用的小一點(必須通過實際運行程式來找到最佳尺寸)。使用allocateDirect替代allocate,以產生一個與作業系統有更高耦合性的“直接”緩衝器還有可能達到更高的速度。但是,這種分配會增加開支,並且具體的實現也隨作業系統的不同而不同。 read()和flip():一旦調用read()來告知FileChannel向ByteBuffer儲存位元組,就必須調用緩衝器上的flip(),讓它做好讓別人讀取位元組的準備。如果打算使用緩衝器執行進一步的read()操作,我們也必須調用clear()來為每個read()做好準備。如下例:
public class ChannelCopy {    private static final int BSIZE = 2014;    public static void main(String[] args) throws IOException {        FileChannel in = new FileInputStream("src/main/resources/in.txt").getChannel();        FileChannel out = new FileOutputStream("src/main/resources/out.txt").getChannel();        ByteBuffer buffer = ByteBuffer.allocate(BSIZE);        while(in.read(buffer) != -1){            buffer.flip();  // 準備寫            out.write(buffer);            buffer.clear();  // 準備讀        }        /**          * 常用的是直接使用transferTo 或者 transferFrom          *///        in.transferTo(0, in.size(), out);//         或者out.transferFrom(in, 0, in.size());    }}

  這裡有兩個FileChannel,一個用於讀,一個用於寫。每次read()操作之後,就會將資料輸入到緩衝器中,flip()則是準備緩衝器以便它的資訊可以由write()提取。write()操作之後,資訊仍在緩衝區中,接著clear()操作則對所有的內部指標重新安排,以便緩衝器在另一個read()操作期間能夠做好接收資料的準備。
  檔案內容複寫之類的操作,一般使用transferTo或者transferFrom方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.