Buffer简介
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
Buffer的作用
与channel进行交互,数据写入和读出都不是硬盘直接与channel进行交互。
1、写入:先从硬盘写入到buffer,然后再将数据从buffer中写入到channel。
2、读出:从将数据从channel中读取到buffer里,再将数据从Buffer读出。
Buffer的类型
1、byteBuffer
2、shortBuffer
3、intBuffer
4、doubleBuffer
5、longBuffer
6、floatBuffer
7、charBuffer
Buffer的基本用法
1、创建缓冲区,从硬盘将文件写入数据到Buffer
position往后移相应的字符长度
2、调用flip()方法将缓冲区改成读取模式
即将position设置为0,limit为position当前所在位置
3、调用buffer的get()方法从buffer中读取数据
调用get()时,读取一位字符,然后将position往后移一位,limit不变
4、调用clear()方法或者compact()方法清空缓存区
清空缓存区并不一定是指将数据清空。
创建缓冲区的两种方式
ByteBuffer buf = ByteBuffer.allocate(1024);//创建间接缓冲区,大小为1024个字节。
ByteBuffer buf2=ByteBuffer.allocateDirect(1024);//直接缓冲区
区别
间接缓冲区:在堆中开辟,易于管理,垃圾回收器可以回收,空间有限,读写文件速度较慢。
直接缓冲区:不在堆中,物理内存中开辟空间,空间比较大,读写文件速度快,缺点:不受垃圾回收器控制,创建和销毁耗性能。
直接操作Buffer
public static void main(String[] args) {
// 声明一个ByteBuffer对象
ByteBuffer buffer = ByteBuffer.allocate(1024);
// 写入数据
buffer.put("Hello".getBytes());
// 将Buffer切换为读取模式
buffer.flip();
// 读取单个字节
byte data = buffer.get();
System.out.println((char)data);
// 因为前一步已经读取出了一个字符,所以这里必须要减1,否则执行buffer.get(bytes)时判断bytes的长度与遗留字符数量时会抛出异常
// 当然也可以调用buffer.rewind()重置position为0
byte[] bytes = new byte[buffer.limit() - 1];
// 将buffer中的内容读取到bytes数组中,长度为bytes.length()
//public ByteBuffer get(byte[] dst, int offset, int length) {
// checkBounds(offset, length, dst.length);
// if (length > remaining())
// throw new BufferUnderflowException();
// int end = offset + length;
// for (int i = offset; i < end; i++)
// dst[i] = get();
// return this;
// }
buffer.get(bytes);
// 输出数据
System.out.println(new String(bytes));
// 清空缓存区
buffer.clear();
}
Channel与Buffer交互
public static void channelToBuffer(String fileName) {
RandomAccessFile textFile = null;
try {
// 创建文件流
textFile = new RandomAccessFile(fileName, "rw");
// 创建文件传输的channel
FileChannel inChannel = textFile.getChannel();
// 创建buffer缓冲区,并分配1024字节的大小
ByteBuffer buf = ByteBuffer.allocate(1024);
int bytesRead;
// 从通道中读取数据到缓冲区
while ((bytesRead = inChannel.read(buf)) != -1) {
// 反转buffer,将写模式改为读模式
buf.flip();
// 判断缓冲区是否有遗留数据
while (buf.hasRemaining()) {
//获取buffer中的数据
System.out.print((char) buf.get());
}
//将上次分配的1024字节的内容清空,为下次接收做准备
buf.clear();
}
textFile.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Buffer的三个属性
1、capacity
容量,即可容纳的最大数据量,在缓冲区创建时被设定且不能改变
2、limit
写模式下:表示最大能往缓冲区写多少数据
读模式下:上界,缓冲区中当前数据量
3、position
位置,下一个要被读取或写的元素的索引
4、mark
标记,调用mark()来设置mark=position,再调用reset()可以让position恢复标记的位置,即position=mark
Buffer中的常用方法
1、rewind()
将position设置为0,可以重新读取缓存区中的数据
2、flip()
将buffer切换为读取模式,将position设置为0,limit设置为position当前值
3、clear()和compact()
clear:将position指针归0,将limit设置为缓冲区尾,再次写入到缓冲区时,写入多少,position置为多少,切换为读取模式时,limit就为多少,所以不用考虑会读取到残留数据
compact: 将已读取过的数据清除掉,然后将剩余数据移到缓冲区的起始处,再写入新的数据放到残留数据后面
4、mark()和reset()
mark是用于标记position当前值,reset是将position还原为mark值