02 Java NIO 缓冲区buffer详解
缓冲区 Buffer
- 缓冲去Buffer:一个用与特定基本数据类型的容器。
- Java nio中的Buffer主要用于与NIO通道进行交换,数据时从通道读入缓冲区,从缓冲区写入通道。
- Buffer 就想一个数组,保存多个相同类型的数据。Buffer常用的子类:ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer,DoubleBuffer;
缓冲区的基本属性
容量(capacity):表示Buffer缓冲区的最大容量,
缓冲区容量不能为负,创建后不能更改。
限制(limit):第一个不应该读取或写入的数据索引,即位于limit后的数据不可读写。
缓冲去的限制不能为负,不能大于其容量capacity。
位置(position):洗一个要读取或写入的数据的索引。
缓冲去的位置不能为负,不能大于其限制limit。
标记(mark)与 重复(reset):标记时一个索引,通过Buffer中的mark()方法指定Buffer中一个特定的位置position,之后通过调用reset()方法恢复到这个位置position。
标记、位置、限制、容量遵守以下不变式: 0 <= mark <= position <= limit <= capacity
buffer缓冲区常用方法
方 法 | 描 述 |
---|---|
Buffer clear() | 清空缓冲区并返回对缓冲区的引用 |
Buffer flip() | 将缓冲区的界限设置为当前位置,并将当前位置充值为 0 |
int capacity() | 返回 Buffer 的 capacity 大小 |
boolean hasRemaining() | 判断缓冲区中是否还有元素 |
int limit() | 返回 Buffer 的界限(limit) 的位置 |
Buffer limit(int n) | 将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象 |
Buffer mark() | 对缓冲区设置标记 |
int position() | 返回缓冲区的当前位置 position |
Buffer position(int n) | 将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象 |
int remaining() | 返回 position 和 limit 之间的元素个数 |
Buffer reset() | 将位置 position 转到以前设置的 mark 所在的位置 |
Buffer rewind() | 将位置设为为 0, 取消设置的 mark |
缓冲区的管理方式
- 通过allocate()方法分配一个指定大小的缓冲区
- put() 存入数据到缓冲区中
- get() 读取缓冲区中的数据
- flip快速反转,原缓冲区属于写模式,使用flip()方法后,切换读取数据模式(原缓冲区是读模式,切换后为写模式)。
示例
package com.nio;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class NioBufferBased {
public static void main(String[] args) {
bufferMethod();
throwBufferOverflowException();
}
/**
* nio buffer缓冲区常用方法
* allocate() 分配缓冲区大小
* put() 存入数据到缓冲区中
* flip() 读写模式反转
* get() 读取缓冲区数据
*
*/
public static void bufferMethod(){
String str = "12345";
// 1:分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(10);
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
// 2:利用 put() 存入数据到缓冲区中
buf.put(str.getBytes(StandardCharsets.UTF_8));
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
// 3:flip快速反转,原缓冲区属于写模式,使用flip()方法后,切换读取数据模式(原缓冲区是读模式,切换后为写模式。)
buf.flip();
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
// 4. 利用 get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
// 缓冲区目前处于读模式,使用put()写入方法将报错 java.nio.BufferOverflowException
// buf.put("abc".getBytes(StandardCharsets.UTF_8));
// 如果想接着写入数据,需要使用flip()方法
buf.flip();
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
buf.put("abc".getBytes(StandardCharsets.UTF_8));
printCapacityLimitPosition(buf.capacity(), buf.limit(), buf.position());
}
/**
* BufferOverflowException 异常
* 写模式下,不能使用读取方法
* 读模式下,不能使用写入方法
*/
public static void throwBufferOverflowException(){
// 1:分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(10);
// 2:利用 put() 存入数据到缓冲区中
buf.put("hello".getBytes(StandardCharsets.UTF_8));
// 3:flip快速反转,原缓冲区属于写模式,使用flip()方法后,切换读取数据模式(原缓冲区是读模式,切换后为写模式。)
buf.flip();
// 4. 利用 get() 读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
// 缓冲区目前处于读模式,使用put()写入方法将报错 java.nio.BufferOverflowException
//buf.put("abc".getBytes(StandardCharsets.UTF_8));
// 如果想接着写入数据,需要使用flip()方法
buf.flip();
buf.put("abc".getBytes(StandardCharsets.UTF_8));
}
/**
* 打印输出 capacity limit position
*
* @param capacity 容量
* @param limit 限制
* @param position 位置
*/
public static void printCapacityLimitPosition(int capacity, int limit, int position) {
System.out.print("Buffer capacity:" + capacity + "; ");
System.out.print("limit:" + limit + "; ");
System.out.print("position: " + position + "; ");
System.out.println();
}
}