文章目录
一、NIO定义
Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
1.1 核心
通道和缓冲区(Buffer)和Selector,通道表示IO源到IO设备(例如:文件,套接字)的连接,缓冲区底层就是数组
二、Buffer
2.1 定义
一个用于特定基本类型数据的容器。
缓冲区是特定基本类型元素的线性有限序列。
2.2 性质
缓冲区的容量 是它所包含的元素的数量。缓冲区的容量不能为负并且不能更改。
缓冲区的限制 是第一个不应该读取或写入的元素的索引。缓冲区的限制不能为负,并且不能大于其容量。
缓冲区的位置 是下一个要读取或写入的元素的索引。缓冲区的位置不能为负,并且不能大于其限制。
2.3 常用方法
- Buffer flip()
翻转这个缓冲区。
使position指向0位置,limit的位置则不变,为文件的读取做准备。 - Buffer clear()
清除此缓冲区。
使position指向0的位置,limit指向最大的位置
三、参考
3.1 参考
3.1 传统的阻塞I/O模型
- 一个请求需要一个线程区处理
- 阻塞I/O模式下会有大量的线程被阻塞,的导致系统的利用率很差。
- 网络I/O阻塞和网络故障可能导致线程等待的时间更长。
3.2 IO与NIO的区别
- 原有的 IO 是面向流的、阻塞的,(阻塞就是该线程调用read或者wirte方法,直到读到数据或者写出某些数据,不然线程一致会阻塞在这个地方,不能做其他的事情。)NIO 则是面向块的、非阻塞的。(非阻塞就是读取数据时有自己所要的数据的时候就读取,没有自己所要的数据的时候还可以去做其他的事情)。也就是可以一个线程去处理多个操作,而不是1000个线程过来就需要创建1000个线程去处理。
- 原来的IO流不存在缓存的概念,NIO提供缓存的概念,数据被存储在缓存中,可以前后移动来读取所要的数据。
3.3 通道和流的比较
- 通道可以同时进行读和写,而流只能进行度和写。
- 通道可以异步实现读取数据
- 通道可以从缓冲区读数据,也可以写数据到缓冲区。
3.4 读写数据需要注意的问题
- 使用flip方法进行读写模式的转换,将写模式转换为读模式
- 使用clear方法将已经从缓冲区去获取的的数据进行清除。
3.5 常用的字段
-
capacity
缓冲区的容量 -
position
当前读写的位置 -
limit
信息末尾的位置
3.6 缓冲区常用的方法
- clear方法
清空缓存区 - compact方法
只会清空已经读取的数据 - flip方法
向缓存区写变为从缓存区读的状态 - put方法
将字节类型的数据放到缓冲区中 - get方法
取出缓存去中的字节,一次只能取一个
3.7 Selector
可以检测出多个NIO通道,并看看读写是否就绪,多个channel以事件的形式注册到同一个selector,从而使一个线程处理多个请求成为可能。
四、实战操作
4.1 传统的IO读写
字节流
public class ReadTest
{
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream("C:\\Users\\ybx\\IdeaProjects\\QuickKill\\src\\main\\java\\com\\example\\demo\\IO\\ReadTest.java");
byte[] bytes = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(bytes))!= -1){
System.out.println(new String(bytes));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
fileInputStream.close();
}
}
}
字符流:
public class ReadTest
{
public static void main(String[] args) throws IOException {
FileReader read = null;
try {
read = new FileReader("C:\\Users\\ybx\\IdeaProjects\\QuickKill\\src\\main\\java\\com\\example\\demo\\IO\\ReadTest.java");
char[] array = new char[1024];
while (read.read(array) != -1){
System.out.println(new String(array));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
read.close();
}
}
}
使用BufferReader对象进行读写:
public class ReadTest
{
public static void main(String[] args) throws IOException {
BufferedReader read = null;
try {
read = new BufferedReader(new FileReader("C:\\Users\\ybx\\IdeaProjects\\QuickKill\\src\\main\\java\\com\\example\\demo\\IO\\ReadTest.java"));
String line = null;
while ((line = read.readLine()) != null){
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
read.close();
}
}
}
4.2 使用NIO进行读写
public class ReadTest
{
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\ybx\\IdeaProjects\\QuickKill\\src\\main\\java\\com\\example\\demo\\IO\\ReadTest.java");
FileChannel channel = fileInputStream.getChannel();
ByteBuffer allocate = ByteBuffer.allocate(1024);
while (channel.read(allocate) != -1){
//读写模式转换
allocate.flip();
while (allocate.hasRemaining()){
System.out.print((char)allocate.get());
}
allocate.compact();
}
channel.close();
}
}