NIO(一)
1 NIO简介
Java NIO (New IO)是从Java 1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
2 NIO与IO的区别
IO | NIO |
---|---|
面向流 | 面向缓冲区 |
阻塞IO | 非阻塞IO |
无 | 选择器(selectors) |
IO是单向的,输入流:数据从文件/磁盘/网络到程序。
3 通道和缓冲区
Java NIO系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到IO设备(例如:文件、套接字)的连接。若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。
简而言之,通道负责传输,缓冲区负责存储。
3.1 缓冲区
- 缓冲区(Buffer):一个用于特定基本数据类型的容器。由 java.nio包定义的,所有缓冲区都是 Buffer抽象类的子类。
- Java NIO中的Buffer主要用于与NIO通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道中的。
4 缓冲区的数据存取
缓冲区在Java NIO中负责数据的存取。
缓冲区就是数组,用于存储不同数据类型的数据。根据数据类型的不同(boolean除外),提供了相应类型的缓冲区:ByteBuffer、 CharBuffer、 ShotBuffer、 IntBuffer、 LongBuffer、 FloatBuffer、 DoubleBuffer。上述缓冲区的管理方式几乎一致,通过allocate()获取缓冲区。
// 分配一个指定大小的缓冲区
// ByteBuffer继承自Buffer,Buffer核心属性
ByteBuffer buff = ByteBuffer.allocate(1024);
4.1 Buffer的四个核心属性
private int mark = -1;
private int position = 0;
private int limit;
private int capacity;
position:位置,表示缓冲区中正在操作数据的位置;
limit:界限,表示缓冲区中可以操作数据的大小,大于limit的数据不能进行读写;
capacity:容量,表示缓冲区中最大存储数据的容量,一旦声明不能该表。
mark:标记,表示记录当前position的位置。可以通过reset()恢复到mark的位置。
mark <= position <= limit <= capacity
// 1.分配一个指定大小的缓冲区
ByteBuffer buff = ByteBuffer.allocate(1024);
System.out.println(buff.position());// 0
System.out.println(buff.limit());// 1024
System.out.println(buff.capacity());// 1024
// 2.利用put()存入数据到缓冲区
String str = "abcde";
buff.put(str.getBytes());
System.out.println(buff.position());// 5
System.out.println(buff.limit());// 1024
System.out.println(buff.capacity());// 1024
// 3.切换读取数据模式
buff.flip();
System.out.println(buff.position());// 0
System.out.println(buff.limit());// 5
System.out.println(buff.capacity());// 1024
// 4.利用get()读取缓冲区中的数据
byte[] bytes = new byte[buff.limit()];
buff.get(bytes);
System.out.println(new String(bytes, 0, bytes.length));// abcde
System.out.println(buff.position());// 5
System.out.println(buff.limit());// 5
System.out.println(buff.capacity());// 1024
// 5.rewind() 可重复读(回到了第3步)
buff.rewind();
System.out.println(buff.position());// 0
System.out.println(buff.limit());// 5
System.out.println(buff.capacity());// 1024
// 6.清空缓冲区(但是缓冲区中的数据依然存在,只是处于“被遗忘”状态)
buff.clear();
System.out.println(buff.position());// 0
System.out.println(buff.limit());// 1024
System.out.println(buff.capacity());// 1024
System.out.println((char) buff.get());// a
上述第1、2、3步骤如图:
mark属性用法:
@Test
public void test2() {
String str = "abcde";
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put(str.getBytes());
buffer.flip();
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes, 0, 2);
System.out.println(buffer.position());// 2
buffer.mark();// 标记
buffer.get(bytes, 2, 2);
System.out.println(buffer.position());// 4
buffer.reset();// 恢复
System.out.println(buffer.position());// 2
// 判断缓冲区中是否还有剩余数据
if (buffer.hasRemaining()) {
// 获取缓冲区中可以操作的数量
System.out.println(buffer.remaining());
}
}