前言
程序中所有的数据都是以字节流的方式进行传输的,IO是指在主内存与外部设备(磁盘、网络)之间传输数据的过程,当外部设备还未准备就绪时就会出现IO阻塞。基于磁盘操作的 I/O 接口:File,基于网络操作的 I/O 接口:Socket
磁盘IO(文件读写)
// 字节操作的 I/O 接口:InputStream(读) 和 OutputStream(写)
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
// 字节输入流:读数据
bufferedInputStream = new BufferedInputStream(
new FileInputStream(new File("C:\\Users\\lixing\\Desktop\\通话录音.mp3")));
// 字节输出流:写数据
bufferedOutputStream = new BufferedOutputStream(
new FileOutputStream(new File("C:\\Users\\lixing\\Desktop\\通话录音_.mp3")));
// 复制文件
byte[] readBytes = new byte[1024]; // 缓冲大小
int readBytesLen; // 读取字节的长度
while ((readBytesLen = bufferedInputStream.read(readBytes))!= -1) {
bufferedOutputStream.write(readBytes, 0, readBytesLen);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedOutputStream != null) {
try {
bufferedOutputStream.close();
} catch (IOException e) {
System.out.println("bufferedOutputStream关闭失败");
}
}
if (bufferedInputStream != null) {
try {
bufferedInputStream.close();
} catch (IOException e) {
System.out.println("bufferedInputStream关闭失败");
}
}
}
// 字符操作的 I/O 接口:Reader(读)和Writer(写)
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
bufferedReader = new BufferedReader(new FileReader(new File("C:\\Users\\lixing\\Desktop\\demo.txt")));
bufferedWriter = new BufferedWriter(new FileWriter(new File("C:\\Users\\lixing\\Desktop\\demo_.txt")));
String readLine;
while ( (readLine = bufferedReader.readLine()) != null) {
bufferedWriter.write(readLine+"\r\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException e) {
System.out.println("bufferedWriter关闭失败");
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
System.out.println("bufferedReader关闭失败");
}
}
}
网络IO(Socket)
网络 I/O 描述的是计算机之间完成相互通信一种抽象功能。实质是对 Socket 的读取,大部分情况下我们使用的都是基于 TCP/IP 的流套接字,它是一种稳定的通信协议。当客户端和服务端成功建立连接后都会拥有一个 Socket 实例,每个 Socket 实例都有一个 InputStream 和 OutputStream,正是通过这两个对象来交换数据的
同步、阻塞式IO(BIO)
客户端向服务器发起一个请求时,服务器就会为之创建一个线程来处理相关业务,当业务中涉及的IO资源还未准备就绪(即系统内核空间中的资源还未准备就绪),则当前线程将一直处于阻塞状态(导致用户空间阻塞),在高并发场景下,系统会因为创建大量的线程而消耗性能
小明(线程)去火车站买票,发现前面有100个人在排队(系统IO资源还未准备就绪),于是开始排队等待(线程处于阻塞状态),直到这100个人全部结束后再去买票
由于售票窗口的场地有限(系统内存有限),每来一个人就会为其分配一块空间(创建一个线程)去排队,当排队的人很多时(高并发场景),售票窗口的场地会越来越小(系统内存消耗的越来越多),最后场面一片混乱(系统处理请求的性能越来越弱)
同步、非阻塞式IO(NIO)
NIO默认采用的select poll模型,该模型会以轮询的方式去查看系统IO资源的就绪情况。自始至终,买票都是由小明亲操作的--同步
Java在1.5推出了NIO:
小明去火车站买票,发现前面有100个人在排队,于是便离开车站去做其它事情(非阻塞),以后每10分钟来车站查看排队情况(轮询系统IO资源的就绪情况),如果发现没有人排队了则去买票
异步、非阻塞式IO(AIO)
AIO默认采用的是epoll模型,该模型会将待处理的业务委托给操作系统做,操作系统处理好了后以回调的方式通知
买票是由小明发起的,但是不是由小明亲自买的--异步
Java1.7推出了AIO:
小明去车站买票,发现前面有100个人在排队,于是委托黄牛(操作系统)来帮他买票,自己便离开了车站去做其它事情(非阻塞),当黄牛买到票后便通知小明来取(回调通知)
多路 I/O 复用
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程,那顾名思义就是采用指单线程来处理多个网路的IO请求
多路 I/O 复用模型是利用epoll网络模型,可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞状态中唤醒,于是程序就会轮询一遍所有的流(注意epoll只轮询那些真正发出了事件的流),并且依次有序的处理