Java IO
一、Java IO流的40多个类都是从如下4个抽象类派生出来的。
InputStream/Reader:所有的输入流基类,前者是字节输入流,后者是字符输入流。
OutputStream/Reader:前者是字节输出流,或者字符输出流。
解释:流是程序输入或输出的一个连续的字节序列,设备(例如鼠标,键盘,磁盘,屏幕和打印机)的输入和输出都是用流来处理的。在C语言中,所有的流均以文件的形式出现,不一定是物理磁盘文件,还可以是对应与某个输入/输出源的逻辑文件
为什么I/O流操作要分为字节流操作和字符流操作?
个人原因:
1、字符流是由Java虚拟机将字节流转换得到的,计算过程比较耗时。
2、如果不知道编码类型会出现乱码。
音频文件、图片媒体等文件用字节流比较好。
如果涉及到字符,还是字符流比较好。
BIO属于同步阻塞I/O,Blocking I/O
同步阻塞IO模型中,应用程序发起Read调用后,会一直阻塞,直到把内核数据拷贝到用户空间。
在客户端连接数量不高的情况下是没问题的。但是面对十万甚至百万级连接的时候,传统BIO模型是无能为力的。
NIO(Non-blocking)
Channel(通道)、Buffer(缓冲区)、Selector(选择器)
Java中的NIO可以看做I/O多路复用。
同步非阻塞IO模型中,应用程序一直发起read调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到内核把数据拷贝到用户空间。
一直轮询来查看当前数据是否准备好。
NIO重点是把Channel,Buffer,Selector选择器三个类。
其中Selector帮助线程来管理多个Channel。
传统的IO操作基于数据流进行操作,而NIO基于Channel和buffer进行读写。
NIO与传统的IO的区别:
1、IO面向流、NIO面向缓冲区。因为缓冲区的存在,可以在缓冲区进行数据的前后移动,比如拆包和封包。
2、channel和stream的区别,channel是双向读写,stream是单向读写。
每一个channel都会对应一个buffer
一个线程对应一个selector,一个selector对应多个channel连接
程序切换到哪个channel是由事件决定的
selector会根据不同的事件,在各个通道上切换
buffer就是一个内存块,底层是一个数组。
数据的读取写入是通过Buffer完成的,BIO要么是输入流,或者是输出流,不能双向,但是NIO的Buffer是可以读也可以写。
NIO和BIO的比较:
1、BIO以流的方式处理
2、BIO是阻塞的、NIO是非阻塞的
3、BIO基于字节流和字符流进行操作,而NIO基于Channel通道和buffer缓冲区进行操作,数据从通道读入到缓冲区,或者从缓冲区读入到通道。selector监听多个通道事件,因此使用单个线程就可以监听多个客户端通道。
4、Java NIO系统核心在与:通道(channel)和缓冲区(buffer)。通道表示打开IO设备
缓冲区:一个用于特定基本数据类型的容器JavaNIO中的buffer主要用于NIO通道进行交互,数据是从通道读入缓冲区,从缓冲区写入通道的。
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
通过allocate来分配容量。
selector选择器
selector是SelectableChannel对象的多路复用器,selector可以监控多个channel的状况,也就是说,利用selector可使一个单独的线程管理多个channel。selector是非阻塞的IO核心
selector能够检测多个注册通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个时间相应的处理。这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求。
只有在连接/通道 真正有读写发生时候,才会读写,大大减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程。
避免了上下文导致的开销。
通道:由Java、nio、channel包定义的。Channel表示IO源与目标打开的连接。Channel类似于传统的“流”。只不过Channel不能直接访问数据,Channel只能与Buffer进行交互。
AIO、NIO、BIO
AIO:适用于连接数目多且连接比较长的架构,比如相册服务器,充分调用OS参与并发操作,编程复杂。用的较少。
NIO:适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中。
BIO:适用于连接数目少且连接比较小的架构,这种方式多服务器资源要求较高。