java.io中最为核心的一个概念是流(Stream),面向流编程。Java中,一个流要么是输入流,要么是输出流,不可能同时既是输入流又是输出流。
java.nio中拥有三个核心概念:Selector、Channel与Buffer。在java.nio中,我们是面向块(block)或是缓冲区(buffer)编程的。Buffer本身就是一块内存,底层实现上实际是个数组。数据的读写都是通过Buffer来实现的。
除了数组之外,Buffer还提供了对于数据的结构化访问,并且可以追踪到系统的读写过程。
Java中的7种原生数据类型都有各种对应的Buffer类型,如IntBuffer、LongBuffer、ByteBuffer及CharBuffer等,并没有BooleanBuffer类型。
Channel指的是可以向其写入数据或者从中读取数据的对象,类似于java.io中的Stream。
所有的数据都是通过读写Buffer来进行的,永远不会出现直接向Channel中写入数据的情况,或者直接从Channel读取数据的情况。
与Stream不同,Channel是双向的,一个流只可能是InputStream或者是OutputStream,Channel打开后则可以进行读取、写入或是读写。
由于Channel是双向的,因此它能更好的反应出底层操作系统的真实情况,在Linux系统中,底层操作系统的通道就是双向的。
关于NIO Buffer中的3个重要状态属性的含义:position、limit、capacity。
先上段小示例代码:
public class NioTest1 {
public static void main(String[] args) {
IntBuffer buffer = IntBuffer.allocate(10);
for (int i = 0; i < 10; i++) {
int random = new SecureRandom().nextInt(20);
buffer.put(random);//put向buffer写数据
}
//读写转换
buffer.flip();
while (buffer.hasRemaining()) {
System.out.println(buffer.get());//get从buffer读数据
}
}
}
Ron Hitchens写的java nio一书中把nio相关的概念介绍的都明明白白的,这里摘抄一下对Buffer的简介:
- 容量(Capacity) 缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,并且永远不能 被改变。
- 上界(Limit) 缓冲区的第一个不能被读或写的元素。或者说,缓冲区中现存元素的计数。
- 位置(Position) 下一个要被读或写的元素的索引。位置会自动由相应的 get( )和 put( )函数更新。
- 标记(Mark)
一个备忘位置。调用 mark( )来设定 mark = postion。调用 reset( )设定 position =
mark。标记在设定前是未定义的(undefined)。
这四个属性之间总是遵循以下关系: 0 <= mark <= position <= limit <= capacity
调用api的过程中,position、limit、capacity的变化:
最后的小例子:
public class NioTest4 {
public static void main(String[] args) throws Exception {
FileInputStream inputStream = new FileInputStream("input.txt");
FileOutputStream outputStream = new FileOutputStream("output.txt");
FileChannel inputChannel = inputStream.getChannel();
FileChannel outputChannel = outputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(512);
while (true) {
buffer.clear();//如果注释掉该行代码会发生什么情况?
//注释掉buffer.clear()后, 在while循环的最后一句outputChannel.write执行后
// buffer的position等于limit,这样read返回为0
// while循环无法结束,flip会导致每次把buffer的内容重复写入
int read = inputChannel.read(buffer);
System.out.println(read);
if (read == -1) {
break;
}
buffer.flip();
outputChannel.write(buffer);
}
inputChannel.close();
outputChannel.close();
}
}