IO
是指 Input/Output
,即输入和输出。以内存为中心:
Input
指从外部读入数据到内存。例如:把文件从磁盘读取到内存,从网络中读取数据到内存Output
指把数据从内存输出到外部。例如:把数据写入到磁盘中,把数据从内存输出到网络中
IO
流是一种顺序读写数据的模式,它的特点是单向流动。数据类似自来水一样在水管中流动,所以我们把它称为 IO
流。按照输入和输出,IO
流分为输入、输出两种 IO
流,每种输入、输出流又分为字节流和字符流两大类。
- 字节流以字节
byte
为单位处理输入、输出操作 - 字符流以字符
char
为单位处理输入、输出操作InputStream/OutputStream 字节流
从磁盘读入一个文件,包含 6 个字节,就相当于读入了 6 个字节的数据,读取过程是按顺序进行的称为输入字节流
反过来,把 6 个字节从内存写入磁盘文件中则称为输出字节流╔════════════╗
║ Memory ║
╚════════════╝
▲
│0x48
│0x65
│0x6c
│0x6c
│0x6f
│0x21
╔═══════════╗
║ Hard Disk ║
╚═══════════╝
╔════════════╗
║ Memory ║
╚════════════╝
│0x21
│0x6f
│0x6c
│0x6c
│0x65
│0x48
▼
╔═══════════╗
║ Hard Disk ║
╚═══════════╝
在
Java
中,InputStream
是所有输入字节流的基类,OutputStream
是所有输出字节流的基类
Reader/Writer 字符流
把 char[]
数组 Hi你好 这 4 个字符用 Writer
字符流写入文件,并且使用 UTF-8
编码,得到的最终文件是 8 个字节,英文字符 H
和 i
各占一个字节,中文 你好
各占 3 个字节:
0x48
0x69
0xe4bda0
0xe5a5bd
反过来,用 Reader
读取以 UTF-8 编码的这 8 个字节,得到 Hi你好
这 4 个字符。
上述整个过程,Reader
和 Writer
本质上是一个自动编解码的 InputStream
和 OutputStream
。Reader
内部把读入的数据从 byte
转换为了 char
字节流和字符流的用法几乎完全一样,如何选择使用 Reader 和 InputStream 要取决于具体的使用场景。如果数据源不是文本使用 InputStream,反之则使用 Reader
java.io 包
java.io 包中涉及处理 IO 流的有 40+ 类,这些类看起来很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系,这 40+ 类都是从 InputStream/OutputStream、Reader/Writer 4个抽象基类中派生出来的
按操作方式分类结构图:
按操作对象分类结构图:
BIO、NIO 和 AIO 之间的区别
BIO
BIO
指 Blocking I/O
全称同步阻塞 I/O
模型。此模型下数据的读取和写入必须阻塞在一个线程内等待其完成。这种适用于活动连接数不是特别高(小于单机 1000)的应用场景,可以让每一个连接专注于自己的 I/O
并且编码相对简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO
模型是无能为力的
NIO
NIO
指 Non-blocking/New I/O
全称同步非阻塞 I/O
模型。非阻塞模型的应用场景与阻塞模型应用场景相反,它适用于高负载、高并发的(网络)应用。Java 1.4 引入了 NIO
框架,对应 java.nio
包,框架提供了 Channel
,Selector
,Buffer
等抽象,它支持面向缓冲的,基于通道的 I/O
操作方法
AIO
AIO
指 Asynchronous I/O
全称异步非阻塞 I/O
模型。AIO
与 BIO
和 NIO
完全不同,它是一种全新的设计。AIO
是基于事件和回调机制实现的,程序执行代码之后会直接返回,不会造成阻塞,当后台处理完成后,操作系统在通知相应的线程进行后续的操作。Java 7 中引入了 AIO