IO 介绍
# IO 介绍
简单介绍下 IO 的概念和 Java 中 IO 的体系。
# 什么是 IO
在冯诺依曼结构中,IO 是重要的组成部分,几乎所有编程语言都涉及 IO。IO 是指 Input/Output,即输入和输出,这里的输入和输出都是以内存(存储器)为中心的:
- CPU 只处理内存中的数据,因此如果要处理不在内存中的数据,要先将数据输入(Input)到内存,例如将文件加载到内存,或者读取网络上的数据(例如数据库)到内存。
- 内存是易失性的,关机或者宕机后,数据就没有了。所以如果要保存内存中的数据,就得将数据输出(Output)到文件里,或者输出到网络接口(例如数据库)。
我们的 Java 程序也是在内存中由 CPU 运行的,内存中的数据无非就是 0 和 1,这里的 0 和 1 可能是字符数据,也可能是二进制数据,可以用 Java 的 byte[]
,String
来表示并处理。
# 什么是流
在程序中,我们经常需要读取文件,那么如何读取比较好呢?比如一个大文件,不可能瞬间就能读取到内存里,读取速度取决于硬件的性能;并且内存里也不一定有足够的内存放下整个文件。
因此,一个文件的数据,我们都是一部分一部分地读取的。这种读取方式,我们称为流,数据就像水流一样一点一点地流入到内存里;输出也是一样的,向水流一样流出到硬盘上,因此我们也可以称这种读取方式为 IO 流,IO 流是一种顺序读写数据的模式。
字节是计算机存储单元的基本单位,因此 IO 流也可以称为字节流,例如我们读取一个 6 字节大小的文件,相当于读入了 6 个字节的数据:
╔════════════╗
║ Memory ║
╚════════════╝
▲
│0x48
│0x65
│0x6c
│0x6c
│0x6f
│0x21
╔═══════════╗
║ Hard Disk ║
╚═══════════╝
2
3
4
5
6
7
8
9
10
11
12
13
我们按顺序读取这 6 个字节,这种读取方式是输入字节流;
反过来,将 6 个字节存储到磁盘上,就是输出字节流
╔════════════╗
║ Memory ║
╚════════════╝
│0x21
│0x6f
│0x6c
│0x6c
│0x65
│0x48
▼
╔═══════════╗
║ Hard Disk ║
╚═══════════╝
2
3
4
5
6
7
8
9
10
11
12
13
# Java 中的 IO 流
在 Java 中,有许多用于各种目的的 IO 类(例如读取文件的 IO 类,读取网络接口的 IO 类),我们可以简单地将它们分为输入类和输出类:
InputStream
,代表输入字节流。是一个抽象类,所有输入流的超类。OuputStream
,代表输出字节流。也是抽象类,是所有输出流的超类。
图片来自《Java 语言程序设计-基础篇》17.1 节
除了字节之外,我们可能还会读写字符,因此 Java 提供了 Reader
和 Writer
,用来读写字符;但是,计算机中只存储 0 和 1,Reader
和 Writer
本质上也是读取字节流的;只不过他们能在读取字节的时候自动解码为 char 字符,输出字节的时候自动编码为二进制数,所以看起来就是直接读写字符了:
图片来自《Java 语言程序设计-基础篇》17.2 节
我们也可以使用 InputStream
读取字符为 byte[]
数组,然后根据编码转换为字符串。
一般情况下,使用二进制文件的效率更高:
- 例如存储一个整数 199,只需存储 199 的二进制数字 C7 即可;而如果用文本文件,则需存储‘1’,‘9’,‘9’三个字符,需要存储的空间更大
- 二进制 IO 不需要编码和解码,比文本 IO 类效率高
- 二进制文件与主机的编码方案无关,因此是可移植的,在任何机器上的 Java 程序都可以读取 Java 程序所创建的二进制文件,这也是为什么编译后的字节码文件是二进制的原因。
# 同步和异步
同步 IO 是指,读写 IO 时代码必须等待数据返回后才继续执行后续代码,它的优点是代码编写简单,缺点是 CPU 执行效率低。
而异步 IO 是指,读写 IO 时仅发出请求,然后立刻执行后续代码,它的优点是 CPU 执行效率高,缺点是代码编写复杂。
Java 标准库的包 java.io
提供了所有同步 IO 的功能,而 java.nio
则提供了异步 IO。我们只讨论 Java 的同步 IO,对于异步 IO 感兴趣的同学可以去看看 Netty
上面我们讨论的 InputStream
、OutputStream
、Reader
和 Writer
都是同步 IO 的抽象类,要使用 IO 都得使用对应的具体实现类,以读写文件为例,有 FileInputStream
、FileOutputStream
、FileReader
和 FileWriter
。
# 小结
什么是流:流是一种流式的数据输入/输出模型。
在 Java 中,java.io
包提供了同步 IO 功能。主要有两种流:
- 字节流接口:
InputStream
/OutputStream
,所有输入/输出流的父类,二进制数据以byte
为最小单位流动; - 字符流接口:
Reader
/Writer
,字符数据以char
为最小单位流动
Java.nio 则提供了异步 IO。