java nio 緩衝區(一),javanio緩衝區
本文來自於我的個人部落格:java nio 緩衝區(一)
我們以Buffer類開始對java.nio包的瀏覽曆程。這些類是java.nio的構造基礎。這個系列中,我們將跟隨《java NIO》書籍一起深入研究緩衝區,瞭解各種不同的類型,並學會怎樣使用。
一個Buffer對象是固定數量的資料容器。其作用是一個儲存空間,或者分段運輸區,在這裡資料可被儲存並在之後用於檢索。
Buffer類的家譜:
一,緩衝區基礎
1.緩衝區的屬性:
容量(capacity):緩衝區能夠容納的資料元素的最大數量,這一容量是在緩衝區被建立時設定的,並且永遠不能被改變
上界(limit): 緩衝區的第一個不能被讀或寫的元素。或者說,緩衝區中現存元素的計數。
位置(position): 下一個要被讀或寫的元素的索引,位置會自動由相應的get()和put()函數更新。
標記(mark): 一個備忘位置,調用mark()來設定mark=position.調用reset()設定position=mark。標記在設定前是未定義的(undefied)。
這四個屬性的關係如下:
0 <= mark <= position <= limit <= capacity
接下來,我們看看這些屬性在實際應用中的一些例子:
建立一個新的ByteBuffer,則緩衝區的各個屬性狀態如所示:
位置被設定為0,而且容量和上界被設為10,剛好經過緩衝區能夠容納的最後一個位元組。標記最初未定義,容量是固定的,但另外三個屬性可以在使用緩衝區時改變。
2.緩衝區API
讓我們來看看如果使用一個緩衝區,以下是Buffer類的方法:
package java.nio;public abstract class Buffer { public final int capacity(); public final int position(); public final Buffer position(int newPosition); public final int limit(); public final Buffer limit(int newLimit); public final Buffer mark(); public final Buffer reset(); public final Buffer flip(); public final Buffer rewind(); public final int remaining(); public final boolean hasRemaining(); public abstract boolean isReadOnly();}
關於這個API,有一點要注意,像clear()這類方法,通常應當返回void,而不是Buffer引用,這些函數將引用返回到它們在(this)上被引用的對象,這是一個允許級聯調用的類設計方法。級聯調用允許這種類型的代碼:
buffer.mark();
buffer.position(5);
buffer.reset();
被簡寫為:buffer.mark().position(5).reset();
3.存取
我們將代表"Hello"字串的ASCII碼載入一個名為buffer的ByteBuffer對象中,緩衝區的結果狀態如所示:
buffer.put((byte)'H').put((byte)'e').put((byte)'1').put((byte)'1').put((byte)'o');
既然已經在buffer中存放了一些資料,如果我們想在不丟失位置的情況下進行一些更改該怎麼辦呢?put()的絕對方案可以達到這樣的目的。假設我們想將緩衝區中的內容從"Hello"的ASCII碼更改為"Mellow"。我們可以這樣實現:
buffer.put(0,(byte)'M').put((byte)'w');修改後的buffer如所示:
4.翻轉
在我們寫滿了緩衝區之後,現在我們必須準備將其清空。我們想把這個緩衝區傳遞給一個通道,以使內容能被全部寫出,但如果通道現在在緩衝區上執行get(),那麼它將從我們剛剛插入的遊泳資料之外取出未定義的資料,如果我們將位置設定為0,通道就會從正確位置開始擷取,但是它使怎樣知道何時叨叨我們所插入資料末端的呢?這就是上界屬性被引入的目的。buffer.limit(buffer.position()).position(0),但是這種從填充到釋放轉檯的緩衝區翻轉是預先設計好的,設計者為我們提供了更便利的方法buffer.flip(),flip方法將一個能夠繼續添加資料元素的填充狀態的緩衝區飯莊成一個準備讀出元素的釋放狀態,在翻轉之後,緩衝區的狀態如所示:
rewind()方法與flip()方法相似,但是它會改變limit的值,只是將position的值設定為0,這個方法可以用於回退已經度過的資料以便重新讀取已經讀過的資料。
方法hasRemaining會告訴你,是否已經達到緩衝區的上界,即limit-position=0,以下是一種將資料元素從緩衝區釋放到一個數組的方法:
for(int i = 0; buffer.hasRemaining();i++{
byteArray[i] = buffer.get();
}
還有一種選擇是使用remainig()方法,這個方法告訴你還剩餘多少元素數目可被存入,可以根據以下方法釋放緩衝:
int count = buffre.remaining();
for(int i = 0; i < count;i++) {
byteArray[i] = buffer.get();
}
5.下面是一個例子來填充以及釋放緩衝區:
import java.nio.CharBuffer;public class BufferFillDrain{ private static int index = 0; private static String[] strings = { "hello word", "java is very beautiful", "python is very brief" }; public static void main(String[] args) throws Exception{ CharBuffer buffer = CharBuffer.allocate(100); while(fillBuffer(buffer)) { buffer.flip(); drainBuffer(buffer); buffer.clear(); } } private static void drainBuffer(CharBuffer buffer) { while(buffer.hasRemaining()) { System.out.println(buffer.get()); } } private static boolean fillBuffer(CharBuffer buffer) { if(index >= strings.length) { String string = strings[length]; for(int i = 0; i < strings.length(); i++) { buffer.put(string.charAt(i)); } } return true; }}
6.壓縮
有時,我們可能只想從緩衝區中釋放一部分資料,而不是全部,然後重新填充,為了實現這一點,未讀的資料元素需要下移以使第一個元素索引為0,而API對此提供了一個compact()方法,在釋放緩衝區以前,可能有個緩衝區如下所示:
調用buffer.compact()方法之後,緩衝區的狀態如所示:
可以看到,已經將釋放的位元組剔除,然後position的位置將會變為limit - originPosition,limit則被設定為limit=capacity。然後又重新從position位置填充資料。
7.緩衝區的比較
兩個被認為是相同緩衝區的條件是從position位置開始到limit位置結束,這段位元組之內的資料相同,則說明兩個緩衝區相同,比較方法為buffer.compareTo(buffer),如所示兩個緩衝區相同:
JAVA NIO的問題
是直接把檔案通道映射到記憶體中的?有中文的話肯定有字元位元組轉換問題,用BufferedReader一行一行讀,然後分配一個ByteBuffer緩衝區來存一行資料作處理試試吧
java nio 是什?
nio是java New IO的簡稱,在jdk1.4裡提供的新api。Sun官方標榜的特性如下:
– 為所有的原始類型提供(Buffer)緩衝支援。
– 字元集編碼解碼解決方案。
– Channel:一個新的原始I/O抽象。
– 支援鎖和記憶體對應檔的檔案提供者。
– 提供多路(non-bloking)非阻塞式的高伸縮性網路I/O。