我们知道JAVA NIO包含三大核心概念:缓存(buffer),通道(channel)和选择器(selector)。今天我们先看一下Buffer。
NIO中缓存的作用跟传统IO一样,都是为了提高读写性能而创建。但是在具体的使用细节上有所不同,为了方便对比,我们先看一下传统IO中buffer的使用。
传统IO中buffer的使用
在传统的IO中,不管是输出流还是输入流,我们都可以使用buffer来提高读写性能,具体来说,buffer的创建可以分为两类
自己创建buffer
我们可以根据情况创建自己的buffer,比如我们要读取内容:Hello world!,然后输出:
try(InputStream in = new ByteArrayInputStream("Hello world!".getBytes())){
byte[] buffer = new byte[5];
int data;
while ((data = in.read(buffer)) != -1){
for(int i=0; i < data; i++){
System.out.print((char)buffer[i]);
}
}
}
catch (IOException e){
e.printStackTrace();
}
上例中我们显示地创建了一个长度为5的buffer(字节数组),你还可以根据情况创建字符数组等,然后在把内容写到buffer中,再读取buffer
使用IO库中自带的buffer
除了自己创建,你也可以使用IO库中的BufferedInputStream或BufferedOutputStream自带的buffer:
try(InputStream in = new ByteArrayInputStream("Hello world!".getBytes())){
BufferedInputStream bufferedIn = new BufferedInputStream(in,5);
int data;
while ((data = bufferedIn.read())!= -1){
System.out.print((char)data);
}
}
catch (IOException e){
e.printStackTrace();
}
上例使用了BufferedInputStream类,并初始化了一个长度为内部buffer
注意:上例中的
read读取的就是in内部buffer,可以看一下BufferedInputStream的read()源码:
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
}
NIO中的Buffer
NIO中的buffer也分为多个类型:ByteBuffer,CharBuffe,DoubleBuffer等,我们以ByteBuffer为例来看一下如何在NIO中使用buffer:
try{
RandomAccessFile rfa = new RandomAccessFile("d:\\temp1.txt","rw");
FileChannel channel = rfa.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(20);
while (channel.read(buffer) != -1){
buffer.flip();
while (buffer.hasRemaining()){
System.out.print((char) buffer.get());
}
buffer.clear();
}
channel.close();
}
catch (IOException e){
e.printStackTrace();
}
上面实例化了一个长度为20的buffer,不过在NIO中有了专门的缓存对象来处理不同的数据类型。此外,还应注意以下区别:
1.在读取buffer中的内容时,必须要先调用flip()方法,确保channel从写模式切换到了读模式
2.使用get()方法读取内容
3.当读取完毕后使用clear()来关闭buffer。一定要记得调用clear(),否则将导致上例中外层while死循环
注意:
clear方法并没有真正清除数据,只是设置了position为0。因为方法内部能保证position,limit无论在读和写时都能指向正确位置,所以即使不清除已读数据,也不会导致数据混乱。