新的輸入/輸出
(NIO) 庫是在 JDK 1.4 中引入的。NIO 彌補了原來的 I/O 的不足,它在標準 Java 代碼中提供了高速的、面向塊的 I/O。通過定義包含資料的類,以及通過以塊的形式處理這些資料。
一.io與nio的區別
面向流 的
I/O 系統一次一個位元組地處理資料。一個輸入資料流產生一個位元組的資料,一個輸出資料流消費一個位元組的資料。為流式資料建立過濾器非常容易。連結幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。 一個 面向塊 的
I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個資料區塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。
二.通道和緩衝區
通道 和 緩衝區 是 NIO 中的核心對象,幾乎在每一個 I/O 操作中都要使用它們。
通道是對原 I/O 包中的流的類比。到任何目的地(或來自任何地方)的所有資料都必須通過一個 Channel 對象。一個 Buffer 實質上是一個容器物件。發送給一個通道的所有對象都必須首先放到緩衝區中;同樣地,從通道中讀取的任何資料都要讀到緩衝區中。
在本節中,您會瞭解到 NIO 中通道和緩衝區是如何工作的。
什麼是緩衝區?
Buffer 是一個對象, 它包含一些要寫入或者剛讀出的資料。 在 NIO 中加入 Buffer 對象,體現了新庫與原 I/O 的一個重要區別。在面向流的 I/O 中,您將資料直接寫入或者將資料直接讀到 Stream 對象中。
在 NIO 庫中,所有資料都是用緩衝區處理的。在讀取資料時,它是直接讀到緩衝區中的。在寫入資料時,它是寫入到緩衝區中的。任何時候訪問 NIO 中的資料,您都是將它放到緩衝區中。
緩衝區實質上是一個數組。通常它是一個位元組數組,但是也可以使用其他種類的數組。但是一個緩衝區不 僅僅 是一個數組。緩衝區提供了對資料的結構化訪問,而且還可以跟蹤系統的讀/寫進程。
緩衝區類型
最常用的緩衝區類型是 ByteBuffer。一個 ByteBuffer 可以在其底層位元組數組上進行 get/set 操作(即位元組的擷取和設定)。
ByteBuffer 不是 NIO 中唯一的緩衝區類型。事實上,對於每一種基本 Java 類型都有一種緩衝區類型:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
每一個 Buffer 類都是 Buffer 介面的一個執行個體。 除了 ByteBuffer,每一個 Buffer 類都有完全一樣的操作,只是它們所處理的資料類型不一樣。因為大多數標準 I/O 操作都使用 ByteBuffer,所以它具有所有共用的緩衝區操作以及一些特有的操作。
現在您可以花一點時間運行 UseFloatBuffer.java,它包含了類型化的緩衝區的一個應用例子。
什麼是通道?
Channel是一個對象,可以通過它讀取和寫入資料。拿 NIO 與原來的 I/O 做個比較,通道就像是流。
正如前面提到的,所有資料都通過 Buffer 對象來處理。您永遠不會將位元組直接寫入通道中,相反,您是將資料寫入包含一個或者多個位元組的緩衝區。同樣,您不會直接從通道中讀取位元組,而是將資料從通道讀入緩衝區,再從緩衝區擷取這個位元組。
三.讀寫檔案樣本
讀檔案
而在 NIO 中,情況稍有不同:我們首先從 FileInputStream 擷取一個 Channel 對象,然後使用這個通道來讀取資料。
在 NIO 系統中,任何時候執行一個讀操作,您都是從通道中讀取,但是您不是 直接 從通道讀取。因為所有資料最終都駐留在緩衝區中,所以您是從通道讀到緩衝區中。
因此讀取檔案涉及三個步驟:(1) 從 FileInputStream 擷取 Channel,(2) 建立 Buffer,(3) 將資料從 Channel 讀到 Buffer 中。
第一步是擷取通道。我們從 FileInputStream 擷取通道:
FileInputStream fin = new FileInputStream( "readandshow.txt" );FileChannel fc = fin.getChannel(); |
下一步是建立緩衝區:
ByteBuffer buffer = ByteBuffer.allocate( 1024 ); |
最後,需要將資料從通道讀到緩衝區中,如下所示:
您會注意到,我們不需要告訴通道要讀 多少資料 到緩衝區中。每一個緩衝區都有複雜的內部統計機制,它會跟蹤已經讀了多少資料以及還有多少空間可以容納更多的資料。我們將在 緩衝區內部細節 中介紹更多關於緩衝區統計機制的內容。
寫檔案
在 NIO 中寫入檔案類似於從檔案中讀取。首先從 FileOutputStream 擷取一個通道:
FileOutputStream fout = new FileOutputStream( "writesomebytes.txt" );FileChannel fc = fout.getChannel(); |
下一步是建立一個緩衝區並在其中放入一些資料 - 在這裡,資料將從一個名為 message 的數組中取出,這個數組包含字串 "Some bytes" 的 ASCII 位元組(本教程後面將會解釋 buffer.flip() 和 buffer.put() 調用)。
ByteBuffer buffer = ByteBuffer.allocate( 1024 );for (int i=0; i<message.length; ++i) { buffer.put( message[i] );}buffer.flip(); |
最後一步是寫入緩衝區中:
注意在這裡同樣不需要告訴通道要寫入多資料。緩衝區的內部統計機制會跟蹤它包含多少資料以及還有多少資料要寫入。
- Java NIO系列教程(一) Java NIO 概述
- Java NIO系列教程(二) Channel
- Java NIO系列教程(三) Buffer
- Java NIO系列教程(四) Scatter/Gather
- Java NIO系列教程(五) 通道之間的資料轉送
- Java NIO系列教程(六) Selector
- Java NIO系列教程(七) FileChannel
- Java NIO系列教程(八) SocketChannel
- Java NIO系列教程(九) ServerSocketChannel
- Java NIO系列教程(十) Java NIO DatagramChannel
- Java NIO系列教程(十一) Pipe
- Java NIO系列教程(十二) Java NIO與IO