NIO(Non-blocking I/O)是Java中提供的一种I/O操作方式,与传统的I/O方式相比,具有更高的效率和可扩展性。下面来详细介绍NIO的底层实现机制和相关概念。
- Channel
Channel是NIO中的一个基础概念,表示数据源与目标的连接通道。在NIO中,所有的I/O操作都是通过Channel进行的。Channel类似于传统I/O中的文件描述符,但它可以同时支持读写操作,并且可以使用非阻塞模式进行操作。常见的Channel类型包括FileChannel、SocketChannel和ServerSocketChannel等。
- Buffer
Buffer是NIO中的另一个重要概念,用于存储数据。Buffer是一个数组对象,可以容纳多个元素,其中每个元素可以是基本数据类型或其他对象类型。Buffer类似于传统I/O中的缓冲区,但它可以根据需要自动增长或收缩,并支持直接内存访问,因此具有更高的效率和灵活性。常见的Buffer类型包括ByteBuffer、ShortBuffer和CharBuffer等。
- Selector
Selector是NIO中的第三个重要概念,用于多路复用和事件驱动式I/O。在NIO中,可以使用Selector来同时监视多个Channel对象的状态,并在有I/O事件发生时进行响应处理。Selector可以将一个线程绑定到多个Channel上,从而允许在单个线程中同时处理多个I/O请求。
- Channel和Buffer的操作
NIO中的读写操作是通过Channel和Buffer对象进行的。为了进行读取或写入,需要先将数据放入Buffer缓冲区中,然后再通过Channel将其传输到目标位置。当数据被写入Channel时,Buffer会自动切换为读模式;而当数据从Channel中读取时,Buffer会自动切换为写模式。可以使用Buffer类的flip()方法来切换Buffer的模式。
- 非阻塞模式和选择器
NIO提供了非阻塞模式和选择器机制,用于实现高效率、高可扩展性的网络编程。在非阻塞模式下,I/O操作不会阻塞线程,而是立即返回,并由应用程序负责处理I/O事件。这样可以避免线程阻塞并提高系统的并发处理能力。在选择器机制下,可以将一个线程同时绑定到多个Channel上,并使用Selector监视这些Channel的状态。当Channel发生I/O事件时,Selector会通知应用程序进行处理。
public static byte[] toByteArrayNIO(String filename) throws IOException {
//1.获取文件路径,检查是否存在
File file = new File(filename);
if (!file.exists()) {
throw new FileNotFoundException(filename);
}
//2.创建FileInputStream对象和FileChannel对象,并使用FileChannel对象将输入流数据读取到ByteBuffer缓冲区中。
FileChannel channel = null;
FileInputStream fs = null;
try {
fs = new FileInputStream(file);
channel = fs.getChannel();
//3.1 创建一个指定大小的buffer对象
ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
//3.2 从channel对象中读取数据并放入缓冲区(只要字节>0,while这里一直读取)
while (channel.read(byteBuffer) > 0) {
// System.out.println("reading");
}
//3.3 将ByteBuffer缓冲区内容复制到一个byte数组中,并返回该数组
return byteBuffer.array();
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
//4.在finally块中关闭FileChannel对象和FileInputStream对象
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
fs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}