参考
Demo 源码:
https://github.com/huangzhenshi/IO_NIO_NIO2Dem
概述
- BIO基于流的单向操作
- NIO是通过Channel和Buffer缓冲池双向操作
- AIO Channel来操作,AIO依赖操作系统的实现来将来回调
IO流的主要应用场景:
- 文件读写和存储操作(文本、图片、音频、视频文件)
- Socket编程(TCP、UDP)(聊天室、图片和文件上传、下载)
- 跨系统的交互:Netty(Rocketmq、Dubbo)
三种流的特点
- 读写文件方面,随着JDK的发展,陆续完善了IO流的读写功能,所以单就文件的读写而言,版本越高,API越方便,代码越简洁
- BIO:阻塞式,适合小并发,大文件的传输,性能最好
- NIO:异步非阻塞,适合大并发,小文件的传输,多路绑定一个Selector,循环遍历Selector线程来响应所有子线程的事件,比如微信的文字聊天
- AIO:异步将来式、异步回调式,适合大并发,重操作,大文件传输的业务场景
3种IO流的区别
- 文件读写删等操作:
-
BIO最原始,文件读写操作:输入文件、输出文件、输入流、输入缓冲流、输出流、输出缓冲流,完成一个读写操作
-
NIO基于JDK1.4,但并不支持非阻塞的文件操作,基于FileChannel和各种Buffer,存储内容和操作管道解耦,而不像BIO把这些操作都耦合在流上面,Channel支持很多高级操作,比如transferTo三行代码就能实现从一个文件读取数据到另外一个文件
-
AIO基于JDK1.7,支持多个的功能:基于Path和Files的文件和文件夹的复制、移动、删除(都不需要FileChannel),获取和改变文件的属性(RW读写属性、最后修改时间和大小),支持监听文件的变化,还封装了很多API操作文件。
-
AIO不基于工具类,而是基于AsynchronousFileChannel支持两种文件读写的操作:将来回调式和非阻塞式Future对象的方式。
- Socket编程:BIO不适合高并发,但是代码简单,响应速度也快。高并发小流量的操作交给NIO,高并发重操作交给AIO
-
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解;
BIO的编程方式简单粗暴,就是阻塞式:服务端阻塞式监听到一个客户端,就单独开启一个子线程阻塞式的监听客户端的消息,客户端连接成功以后,也是阻塞式的监听服务端写入的消息 -
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持;
NIO的编程方式非阻塞式循环遍历:是服务端和客户端各自都注册一个Selector,然后循环遍历Selector的事件 -
AIO方式适用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持
AIO的编程方式分为2种,将来式和回调式,回调式的方法用的监听回调类比较多,比如AcceptHandler、ReadHandler、WriteHandler、ConnectHandler,但是每个回调类的功能单一
核心类演示
BIO:输入流:输出流、文件流、缓冲流
FileInputStream fis= new FileInputStream(new File(fileFrom));
InputStreamReader isr = new InputStreamReader(fis, "GBK");
BufferedReader br = new BufferedReader(isr);
FileOutputStream fos = new FileOutputStream(fileTo);
OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
BufferedWriter bw = new BufferedWriter(osw);
String input;
while ((input = br.readLine()) != null) {
System.out.println(input);
bw.write(input);
bw.newLine();
}
NIO:
- Channel: FileChannel(阻塞式文件操作)、DatagramChannel(UDP)、SocketChannel(TCP)、ServerSocketChannel(TCP)
- Buffer:ByteBuffer、CharBuffer
- Selector:
- Pipe: 只支持数据单向流动的channel
- 利用函数transferFrom复制文本
RandomAccessFile fromFile = new RandomAccessFile(fileFrom, "rw");
FileChannel fromChannel = fromFile.getChannel();
RandomAccessFile toFile = new RandomAccessFile(fileTo, "rw");
FileChannel toChannel = toFile.getChannel();
long position = 0;
long count = fromChannel.size();
toChannel.transferFrom(fromChannel, position, count);
- 通过常规的Channel、Buffer进行文本的复制,2个Channel对一个ByteBuffer进行操作
RandomAccessFile aFile = new RandomAccessFile(fileFrom, "rw");
RandomAccessFile toFile = new RandomAccessFile(fileTo, "rw");
FileChannel inChannel = aFile.getChannel();
FileChannel toChannel = toFile.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
while (inChannel.read(buf) != -1) {
buf.flip();
toChannel.write(buf);
buf.clear();
}
AIO:
- Path:可以指向文件或文件夹,很多情况下,可以用Path来代替File类,和Files类配合着用。
- Files 工具类: readAllLines ,write ,copy,deleteIfExists
- AsynchronousFileChannel: 用于文件异步读写;
- AsynchronousSocketChannel: 客户端异步socket;
- AsynchronousServerSocketChannel: 服务器异步socket。
文本复制
Path sourcePath= Paths.get(fileFrom);
Path descPath= Paths.get(fileTo);
Files.copy(sourcePath, descPath);
网友评论