一、Buffer的定義
- 用于特定原始類型資料的容器。其已知直接子類有:
,ByteBuffer
,CharBuffer
,DoubleBuffer
,FloatBuffer
,IntBuffer
,LongBuffer
ShortBuffer
- 緩沖區本質上是一塊可以寫入資料,然後可以從中讀取資料的記憶體。這塊記憶體被包裝成NIO Buffer對象,并提供了一組方法,用來友善的通路該塊記憶體。
- Java NIO中的Buffer可用于和NIO通道進行互動。如你所知,資料是從通道讀入緩沖區,從緩沖區寫入到通道中的。// need an example
- 緩沖區是特定原始類型的元素的線性有限序列。
- 緩沖區不能安全地被多個并發線程使用。 如果一個緩沖區被多個線程使用,則應該通過适當的同步來控制對緩沖區的通路
二、基本屬性
capacity
作為一個記憶體塊,Buffer有一個固定的大小值,代表了緩沖區最大可寫入的元素數量
position
下标,初始的position值為0,position表示目前的位置。相對讀寫(讀寫方法分為相對以及絕對兩種類型,後面介紹)都從該位置開始。每次讀寫,position都會移動到下一個Buffer單元。position最大可為capacity – 1(下标從0開始,對應capacity個元素)
有多個方法都會對position重新指派,最直接的方式
/**
* 對position進行指派,如果新值小于mark,那麼mark值将會被舍棄重新指派為預設值-1
*/
public final Buffer position(int newPosition) {
if ((newPosition > limit) || (newPosition < 0))
throw new IllegalArgumentException();
position = newPosition;
if (mark > position) mark = -1;
return this;
}
當調用filp()方法将Buffer從寫模式切換到讀模式,position會被重置為0
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
limit
在寫模式下,Buffer的limit表示你最多能往Buffer裡寫多少資料。 寫模式下,limit始終等于Buffer的capacity。
當切換Buffer到讀模式時, limit表示你最多能讀到多少資料。是以,當切換Buffer到讀模式時,limit會被設定成寫模式下的position值。換句話說,你能讀到之前寫入的所有資料(limit被設定成已寫資料的數量,這個值在寫模式下就是position)
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
mark
标記,調用mark()函數會将mark設為目前的position值
public final Buffer mark() {
mark = position;
return this;
}
通常與reset()方法結合使用,來實作狀态的恢複
public final Buffer reset() {
int m = mark;
if (m < 0)
throw new InvalidMarkException();
position = m;
return this;
}
這幾個變量之間存在關系 0 <= mark <= position <= limit <= capacity
三、Buffer中讀模式和寫模式的切換
寫模式
從position位置開始(假如Buffer中已存在元素,則position不為0),最大限制為limit,此時limit等于capacity,每次寫入一個資料後,position指針會跟着往下移動
寫模式轉換為讀模式
調用flip()方法,從寫模式切換到讀模式時,position重置為0,從第一個元素開始開始讀,最多可讀元素個數limit等于讀模式下的position值,即已寫入的元素個數。
讀模式切換為寫模式
- 如果一次性讀完了所有資料,使用clear()函數将position指針指向0,limit等于capacity
/**
* Clears this buffer. The position is set to zero, the limit is set to
* the capacity, and the mark is discarded.
*/
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
- 如果一次不讀完所有資料,留下了一個空間沒有讀取,使用compact()函數将沒有讀取的資料拷貝到頂端去,limit指針指向第一個可寫入元素的空位置,limit重新指向capacity
不會畫圖,相關文章參考https://blog.csdn.net/Funny_Ma/article/details/103534022
四、Buffer的配置設定
要想獲得一個Buffer對象首先要進行配置設定。 每一個Buffer類都有一個allocate方法
ByteBuffer buf = ByteBuffer.allocate(48);
CharBuffer buf = CharBuffer.allocate(1024);
五、讀寫資料
- 所有Buffer子類都定義了兩類get/put方法(可選擇性實作),相對的get/put方法是從目前position進行操作,每次操作都會對position進行變更,而絕對的get/put方法需要參數指定下标,從指定位置進行操作,不會更改position。如ByteBuffer中的定義
/**
* Relative <i>put</i> method <i>(optional operation)</i>.
* 注意,這裡是可選實作
* <p> Writes the given byte into this buffer at the current
* position, and then increments the position. </p>
*
*/
public abstract ByteBuffer put(byte b);
/**
* Absolute <i>get</i> method. Reads the byte at the given index.
*/
public abstract byte get(int index);
- 通過通道讀入緩沖區,以及從緩沖區寫入到通道中
int bytesRead = inChannel.read(buf); //read into buffer.
int bytesWritten = inChannel.write(buf); //write into buffer.
其他相關API在了解第二點中的基本屬性後,檢視源碼很好了解,這裡就不一一介紹了。