我们知道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
无论在读和写时都能指向正确位置,所以即使不清除已读数据,也不会导致数据混乱。