原文連接:http://tutorials.jenkov.com/java-nio/buffers.html,若有侵權,立刪。html
Java buffer 和 channel 是相輔相成的,正如前文所言,經過channel寫入數據到buffer中,經過channel從buffer中讀取數據。java
buffer是一個高校的內存塊,供你寫入數據用。這些內存塊在buffer中被包裝起來了,而且提供了方法讓你輕鬆使用內存塊。緩存
用buffer進行讀取或寫入數據,一般有以下四個步驟:app
當你向buffer中寫入數據,buffer會保存你向其中寫入了多少個byte。一旦你從buffer中讀取數據,你須要將buffer從寫模式轉化爲讀模式,經過flip()方法。dom
一旦你讀取到全部的data後,你須要清空緩存區,讓buffer爲下一次寫入作準備。你能夠經過兩種方法,clear()和compact()。clear()方法會清空全部的緩存,compact()方法僅僅清空你已經讀過的數據。沒有讀過的數據會被轉移到buffer的開始處,會在沒有讀過的數據後寫入新數據。this
如下是一個簡單的例子spa
1 RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw"); 2 FileChannel inChannel = aFile.getChannel(); 3 4 //create buffer with capacity of 48 bytes 5 ByteBuffer buf = ByteBuffer.allocate(48); 6 7 int bytesRead = inChannel.read(buf); //read into buffer. 8 while (bytesRead != -1) { 9 10 buf.flip(); //make buffer ready for read 11 12 while(buf.hasRemaining()){ 13 System.out.print((char) buf.get()); // read 1 byte at a time 14 } 15 16 buf.clear(); //make buffer ready for writing 17 bytesRead = inChannel.read(buf); 18 } 19 aFile.close();
position和limit的含義會隨着buffer的模式轉換而不一樣,capacity不管哪種模式,含義都是相同的。放兩張圖上來code
Capacity,在建立一個緩存區時,緩存區的大小是固定的。你只能向緩存區中寫入capacity的數據量,一旦緩存區滿了,你須要在下一次寫入新的數據時,經過clear()方法清空緩存區。htm
position,當你想緩存區寫入數據時,你須要清楚你寫到了哪一個位置。position初始化爲0,寫入多少byte,position就會移動多少。position的最大值是capacity-1。blog
當你從緩存區讀取數據時,要從給定的position處開始讀。當你使用flip()方法,將buffer的寫模式轉換爲讀模式。position會被初始化爲0,當你從buffer中讀取出數據時,position會提早移到下一個要讀的位置。
limit,在寫模式中,limit就表明着你能夠向buffer中寫入多少數據,在寫模式中limit等於capacity。
當轉換buffer爲讀模式時,limit意味着你能夠讀取多少數據。所以,當buffer轉換爲讀模式時,limit會被賦值爲寫模式中的position。另外一種是,你寫進去多少數據就讀多少數據(limit被賦值爲寫入buffer中的字節數)
Java NIO 有如下幾種buffer類型
正如你所看見的那樣,不一樣的buffer類型表明了不一樣的基本數據類型。
MappedByteBuffer是一種特殊的buffer類型,以後再討論它。
在得到buffer以前,你必須進行分配。每個Buffer類都有allocate()方法來進行分配,這裏有一個例子,展現如何分配內存
ByteBuffer buf = ByteBuffer.allocate(48);
你能夠經過兩種方法向buffer寫入數據
例子:
1 int bytesRead = inChannel.read(buf); //read into buffer.
1 buf.put(127);
這裏還有不少put()方法的其餘版本,容許你經過不一樣的方法向buffer中寫入數據。
flip()方法將buffer從寫模式轉化爲讀模式。做用看代碼:
1 public final Buffer flip() { 2 limit = position; 3 position = 0; 4 mark = -1; 5 return this; 6 }
這裏有兩種從buffer中讀取數據的方法
例子:
1 //read from buffer into channel. 2 int bytesWritten = inChannel.write(buf);
1 byte aByte = buf.get();
一樣,也有不少版本的get()方法供你使用。
先貼上代碼:
1 public final Buffer rewind() { 2 position = 0; 3 mark = -1; 4 return this; 5 }
將position賦值爲0,其他的不作變化。能夠從頭開始讀取數據。
一旦你從buffer中讀取完數據,你必須讓buffer準備好下一次寫入。你能夠調用clear()方法和compact()方法。
clear方法,會將position設置爲0,仍是上源碼吧
1 public final Buffer clear() { 2 position = 0; 3 limit = capacity; 4 mark = -1; 5 return this; 6 }
源碼的註釋說明:實際上clear()方法並不會將數據從緩存區中擦除,只是名字搞的鬼,由於大多數狀況他確實會被用類清除數據
compact()方法,會將你沒有讀完的數據複製到buffer的開始處,而後將position設置爲未讀數據的下一個位置。
在buffer中你能夠調用mark()方法標記一個給定的position位置,以後你能夠經過調用reset()方法,從新設置position到剛剛mark()的位置。能夠本身試驗下
1 buffer.mark(); 2 3 //call buffer.get() a couple of times, e.g. during parsing. 4 5 buffer.reset(); //set position back to mark.
兩個比較buffer的方法
equals(),當知足如下條件時,爲true
正如你所看到的,equals()只能判斷buffer的一部分數據。直接上源碼
1 public boolean equals(Object ob) { 2 if (this == ob) 3 return true; 4 if (!(ob instanceof ByteBuffer)) 5 return false; 6 ByteBuffer that = (ByteBuffer)ob; 7 if (this.remaining() != that.remaining()) 8 return false; 9 int p = this.position(); 10 for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) 11 if (!equals(this.get(i), that.get(j))) 12 return false; 13 return true; 14 }
compareTo(),直接上源碼了
1 public int compareTo(ByteBuffer that) { 2 int n = this.position() + Math.min(this.remaining(), that.remaining()); 3 for (int i = this.position(), j = that.position(); i < n; i++, j++) { 4 int cmp = compare(this.get(i), that.get(j)); 5 if (cmp != 0) 6 return cmp; 7 } 8 return this.remaining() - that.remaining(); 9 }