Java NIO主要解决了Java IO的效率问题,解决此问题的思路之一是利用硬件和操作系统直接支持的缓冲区、虚拟内存、磁盘控制器直接读写等优化IO的手段;思路之二是提供新的编程架构使得单个线程可以控制多个IO,从而节约线程资源,提高IO性能。
Java IO引入了三个主要概念,即缓冲区(Buffer)、通道(Channel)和选择器(Selector),本文主要介绍缓冲区。
1. 缓冲区概念
缓冲区是对Java原生数组的对象封装,它除了包含其数组外,还带有四个描述缓冲区特征的属性以及一组用来操作缓冲区的API。缓冲区的根类是Buffer,其重要的子类包括ByteBuffer、MappedByteBuffer、CharBuffer、IntBuffer、DoubleBuffer、ShortBuffer、LongBuffer、FloatBuffer。从其名称可以看出这些类分别对应了存储不同类型数据的缓冲区。
1.1四个属性
缓冲区由四个属性指明其状态。
容量(Capacity):缓冲区能够容纳的数据元素的最大数量。初始设定后不能更改。
上界(Limit):缓冲区中第一个不能被读或者写的元素位置。或者说,缓冲区内现存元素的上界。
位置(Position):缓冲区内下一个将要被读或写的元素位置。在进行读写缓冲区时,位置会自动更新。
标记(Mark):一个备忘位置。初始时为“未定义”,调用mark时mark=positon,调用reset时position=mark。
这四个属性总是满足如下关系:
mark<=position<=limit<=capacity
一个新分配的10容量的缓冲区如下图所示:
读取和设置四个属性的代码如下:
/**
* 测试Buffer的各种属性
*/
privatestatic void testProperties() {
CharBuffer buffer = CharBuffer.allocate(10);
//buffer的初始状态
showBuffer(buffer);
//存入三个字符后的状态
buffer.put("abc");
showBuffer(buffer);
//flip后的状态
buffer.flip();
showBuffer(buffer);
//读取两个字符后的状态
charc1= buffer.get();
charc2=buffer.get();
showBuffer(buffer);
//clear后的状态
buffer.clear();
showBuffer(buffer);
}
/**
* 显示buffer的position、limit、capacity和buffer中包含的字符,若字符为0,则替换为'.'
*@param buffer
*/
privatestatic void showBuffer(CharBuffer buffer) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < buffer.limit(); i++) {
char c = buffer.get(i);
if (c == 0) {
c = '.';
}
sb.append(c);
}
System.out.printf("position=%d, limit=%d, capacity=%d,content=%s\n",
buffer.position(),buffer.limit(),buffer.capacity(),sb.toString());
}
mark()是为了暂时性的记住一个position的位置,以便在恰当的时候调用reset()方法让position恢复到此位置,其用法如下:
privatestatic void testMark() {
CharBuffer buffer = CharBuffer.allocate(10);
showBuffer(buffer);
//设置mark位置为3
buffer.position(3).mark().position(5)