天天看點

Java nio Buffer

Buffer是一塊記憶體,主要用在NIO Channel,比如FileChannel,SocketChannel。

對Channel的讀寫都是直接操作Buffer對象。

Buffer是一個工具類,提供了操作這個記憶體塊的方法。

Buffer的實作主要有以下幾種:

Buffer的類型:

  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer

Buffer基本使用

四步搞定

  • 寫資料到Buffer中
  • 調用buffer.flip()
  • 從buffer中讀取資料
  • 調用buffer.clear()或者buffer.compact()

buffer主要有四個主要屬性:

  • capacity: Buffer最大容量
  • position:讀寫偏移
  • limit:最大可讀容量
  • mark: 标記,可以調用reset重讀或重寫

隻要了解了這四個屬性,基本就掌握了Buffer的使用和原理。

我們來看下這三個屬性的說明:

position和limit依賴于Buffer處于讀模式還是寫模式,capacity的意義在讀模式和寫模式都是一樣的

  • 1 capacity:Buffer的最大容量
  • 2 position位置:寫模式下:初始值為0,比如當你put(),putXXX()時,position累加,position最大值是capacity-1

讀模式下:調用Buffer.flip從寫模式切換到讀模式,position被重置為0,其他與寫模式的偏移累加一緻

  • 3 limit:寫模式下:limit的值與capacity一緻

讀模式下:limit用來标志你能夠讀取多少資料,意思就是你隻能讀取寫入的position資料。

  • 4 mark:重置讀寫偏移

讀寫可以參考下圖:

Java nio Buffer

寫模式下,posistion累加,limit和capacity不變,即可以寫入的最大字數。

每次調用一次put()或者putXXXX()時,position+n(n為你寫入的字數,如果寫入一個字,則position+1,如果你寫入字數組,position+數組.長度)

讀模式:當調用flip()時,将limit設定為position,position設定為0,mark設定為-1,limit為能夠讀取的最大字數。

每調用一次get或者getXXX()時,position+n(n為你讀取的字數,如果讀取一個字,則position+1,如果你讀取字數組,position+數組.長度)

Capacity在讀模式和寫模式下都不變。

Buffer.clear()和Buffer.compact()

讀取完資料後,如果想要Buffer能夠再次寫入,可以調用clear和compact函數。

如果調用clear函數,position設定為0.limit設定為capacity,其實裡面的資料并沒有被清除,隻是覆寫寫。

但是有一個場景是,資料沒有讀取完成之前,你需要要先寫入一些資料時,可以調用compact函數,這個函數會把沒有讀取完的資料拷貝到Buffer開始處,然後把position設定為n(n為未讀取資料的長度),limit設定為capacity。

下面是一個簡單的Demo:

// 基本使用
// 建立一個緩沖區,可以存放10個整數
IntBuffer intBuffer = IntBuffer.allocate(10);

// 沒有元素的時候,注意:get的内容int為0,你有可能put 0,是以可以判斷一下position
// 調用intBuffer.position()
// 否則get 會讓position+1
System.out.println("current position should be 0, actually: " + intBuffer.position());
if (intBuffer.position() > 0) {
    int empty_get = intBuffer.get();
}

// 連續放入10個元素
intBuffer.put(1);
intBuffer.put(2);
intBuffer.put(3);
intBuffer.put(4);
intBuffer.put(5);
intBuffer.put(6);
intBuffer.put(7);
intBuffer.put(8);
intBuffer.put(9);
intBuffer.put(10);

// 放入第11個元素時會溢出
try {
    intBuffer.put(11);
} catch (BufferOverflowException e) {
    System.out.println("here should be overflow");
    e.printStackTrace();
}

// 寫模式切換到讀模式
intBuffer.flip();

// 從buffer中讀取資料
int one = intBuffer.get();
System.out.println("read from IntBuffer: should be 1, actually: " + one);
// 重定向讀取位置為0
intBuffer.rewind();
one = intBuffer.get();
System.out.println("read from IntBuffer: should be 1, actually: " + one);

//intBuffer.get(new int[9]);

// 讀模式切換到寫模式
// 将position設定為0, limit設定為capacity
// 如果不想繼續讀取未被讀取的資料,intBuffer.clear();
intBuffer.compact();

intBuffer.put(11);

intBuffer.flip();

// 讀取第一個元素,應該是2
int two = intBuffer.get();
System.out.println("read from IntBuffer: should be 2, actually: " + two);