天天看點

NIO學習01Buffer

一、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);
           

五、讀寫資料

  1. 所有Buffer子類都定義了兩類get/put方法(可選擇性實作),相對的get/put方法是從目前position進行操作,每次操作都會對position進行變更,而絕對的get/put方法需要參數指定下标,從指定位置進行操作,不會更改position。如ByteBuffer中的定義
/**
     * Relative <i>put</i> method&nbsp;&nbsp;<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);
           
  1. 通過通道讀入緩沖區,以及從緩沖區寫入到通道中
int bytesRead = inChannel.read(buf); //read into buffer.
int bytesWritten = inChannel.write(buf); //write into buffer.
           

其他相關API在了解第二點中的基本屬性後,檢視源碼很好了解,這裡就不一一介紹了。

繼續閱讀