一、Buffer基础知识
JAVA NIO中的Buffer用于和NIO通道进行交互,数据从通道读入缓存区,从缓存区写入通道。
缓冲区本质上是一块可以写入数据,也可以读出数据的内存,这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的调用该块内存。
二、Buffer的基本用法
1、使用Buffer读写数据一般有四种个步骤:
- 写入数据到Buffer,Buffer会记录写入了多少数据。
- 调用flip()方法,将Buffer从写模式转换为读模式。
- 从Buffer中读取数据。
- 调用clear()方法或compact()方法。clear()方法会清空缓存区所有的数据,compact()方法只会清除已经读取的数据。
任何未读的数据都会被放到缓存区的起始处,新写入的数据放到缓存区未读取数据的后面。
2、buffer的capacity、position和limit
理解Buffer的工作原理,需要熟悉它的三个属性:capacity、position、limit。
position和limit的含义取决于Buffer处于读模式还是写模式,但capacity的含义一直不变。
capacity:作为一个内存块,Buffer有一个固定的大小,”capacity”。
limit:Buffer在不同的模式下,可以写入或读取数据的多少。但一般情况下,limit都会被设置为之前position的值。
position:当你写入或读取Buffer时,position表示当前的位置,每一次Buffer转换模式时,position都会被初始化为0,position的最大值为capacity-1。
准确理解capacity、position、limit所代表的意义对于理解Buffer有很大的帮助。
3、Buffer的类型
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffe
- IntBuffer
- LongBuffer
- ShortBuffer
这里包含了常见的数据类型,也有map类型的数据。
4、Buffer的分配
要想获得一个Buffef对象,首先要对对象进行分配,每一个Buffer类都有一个allocate()方法,用于分配不同的字节给Buffer。
ByteBuffer buf = ByteBuffer.allocate(1024);//创建一个Buffer,状态为写入状态
5、flip()方法
flip()方法将Buffer从写模式转换为读模式。
调用flip()方法会将position设置为0,并将limit设置为之前position的值。
buf.flip();//反转Buffer,将写入状态转换为写出状态
6、rewind()方法
rewind()方法将position设置为0,所以可以重读Buffer中的所有数据,并且返回一个Buffer。
out.write(buf); // Buffer中写入数据
buf.rewind(); // 重绕缓冲区Buffer
buf.get(array); // Buffer中的数据被替换到array
7、clear()方法和compact()方法
当读取完Buffer中的数据,需要让Buffer准备好再次被写入,可以调用clear()和compact()方法实现。
clear()方法会将position被设置为0,limit被设置为capacity的值。此时Buffer被清空,然后Buffer中的数据并未清除,只是告诉我们该从哪里写入数据。
compact()方法会将所有未读的数据拷贝到Buffer起始处,然后将position设到最后一个未读元素的后面,limit依旧被设置为capacity,现在Buffer写入数据就不会覆盖未读的数据了。
buf.clear();//将Buffer清空,以便下次写入
当你读过源码你就会知道,此方法不能实际清除缓冲区中的数据,但从名称来看它似乎能够这样做,这样命名是因为它多数情况下确实是在清除数据时使用。
8、mark()方法和reset()方法
调用mark()方法可以标记一个特定的position,之后可以通过reset()方法恢复到这个position。
两者的返回值都为Buffer,而且被标记之前的position并不会被丢弃。
9、equals()和compareTo()方法
使用equals()和conoareTo()比较两个Buffer对象
对于equals()方法,当满足下列条件时,两个Buffer相等:
- 相同的类型。
- Buffer中剩余的byte、char等的个数相等。
- Buffer中所有的剩余的byte、char等都相同。
- 返回值:相同时为true,其余为false。
equals()只比较Buffer的一部分,不是每一个在它的元素都比较,实际上,它只比较Buffer中剩余的元素。
compareTo()只比较Buffer的剩余元素byte、char
若满足下列条件,认为一个Buffer小于另一个Buffer:
- 第一个不相等的元素小于另外一个Buffer中对应的元素。
- 比较两个字节缓冲区的方法是按字典顺序比较它们的剩余元素序列,而不考虑每个序列在其对应缓冲区中的起始位置。
- 返回值:正整数、负整数和零。
注:剩余元素是从position到limit之间的元素。
三、Demo
package com.vgbh;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class ChannelDemo {
public void readFromChannelFile () {
try {
RandomAccessFile file = new RandomAccessFile("F:/WorkSpace/TestBook.txt", "rw");//IO的获取文件类
FileChannel fileChannel = file.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);//创建一个Buffer,状态为写入状态
int byteReads = fileChannel.read(buf);//当前buf中的数据长度
while (byteReads != -1) {
System.out.println("ssss " + byteReads + " ssss");
buf.flip();//反转Buffer,将写入状态转换为写出状态
while (buf.hasRemaining()) {
System.out.print((char)buf.get());//获取buf中的数据,将int转换为char,在buf写完后会自动转换为写入状态
}
buf.clear();//将Buffer清空,以便下次写入
byteReads = fileChannel.read(buf);//重新写入新的数据
}
file.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上边的代码只是一个小Demo,有兴趣的可以将其应用到实践中去。
推荐大家可以去看看Java的API文档,有很大的帮助。
有问题的可以联系我的邮箱。