通道就是IO源与目标之间的连接,类似IO中的流,不过通道本身并不能直接访问数据,就像铁路一样,负责传输。
缓冲区就是装载源或目标的容器,类似IO中的byte[],直接操作数据(将文件读入缓冲区,将缓冲区中的数据写入文件),就像火车一样,负责装货。
一句话:通道用于传输,缓冲区用于存取。
除了Boolean类型,其他基本类型都有对应的缓冲区,我们常用的是ByteBuffer。Buffer的重要属性:
private int mark = -1;//标记position的位置,结合reset让position回到当时mark的位置
private int position = 0;// 当前操作数据的位置
private int limit; //可操作数据量
private int capacity;// 缓冲区最大容量
四者的关系:
mark <= position <= limit <= capacity
来张图可能更好理解:
![](https://img.haomeiwen.com/i12064261/4c02f96edeebe802.png)
话不多说,直接上例子:
public void testBuffer(){
String s = "abced";
//allocate分配指定大小的缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println("-------allocate()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//put向缓冲区加入内容
byteBuffer.put(s.getBytes());
System.out.println("-------put()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//flip切换成读模式
byteBuffer.flip();
System.out.println("-------flip()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//get读取缓冲区
byte [] dest = new byte [byteBuffer.limit()];
byteBuffer.get(dest);
System.out.println("读取到的数据"+new String(dest));
System.out.println("-------get()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//rewind恢复到上次读取初始状态,可以重复读取数据
byteBuffer.rewind();
System.out.println("-------rewind()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//clear清空缓冲区,但缓冲区中的数据仍然存在,只是处于被遗忘状态
byteBuffer.clear();
System.out.println("-------clear()-----------");
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
//这里仍然能够读取到
System.out.println((char)byteBuffer.get());
System.out.println("position->"+byteBuffer.position());
System.out.println("limit->"+byteBuffer.limit());
System.out.println("capacity->"+byteBuffer.capacity());
}
mark()和reset()结合使用:
public void testMark(){
String s = "abced";
//allocate分配指定大小的缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
//放入数据
byteBuffer.put(s.getBytes());
//切换到读
byteBuffer.flip();
//读2个字节
byte dest [] = new byte [2];
byteBuffer.get(dest,0,2);
System.out.println(byteBuffer.position());//2
//进行标记
byteBuffer.mark();
//再读2个字节
byteBuffer.get(dest,0,2);
System.out.println(byteBuffer.position());//4
//让position回到上次标记的位置
byteBuffer.reset();
System.out.println(byteBuffer.position());//2
//判断缓冲区是否仍有可操作数据
if(byteBuffer.hasRemaining()){
//还有多少可操作数据
System.out.println(byteBuffer.remaining());//3
}
}
flip()和clear(),应该是操作buffer时候用的最多的。经过测试和分析API(其实看源码可以发现这些方法其实就是在改变buffer的四个属性值),发现如下最佳实践:
- buffer写入之后,读取时,需要先执行flip()。注意这里的读取是指读取buffer,读取和写入是相对的,对文件是写入,对buffer就是读取
- 复用buffer,再次写入之前,最好先执行clear()方法
上代码:
public void testFlip(){
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.put("12345".getBytes());
//写模式切换成读模式
byteBuffer.flip();
String s = new String(byteBuffer.array(),0,byteBuffer.limit());
System.out.println(s);
//复用buffer之前,最好先清空
byteBuffer.clear();
byteBuffer.put("6".getBytes());
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(),0,byteBuffer.limit()));
}
网友评论