搜索 K
Appearance
博客正在加载中...
Appearance
简单介绍下 IO 的概念和 Java 中 IO 的体系。
在冯诺依曼结构中,IO 是重要的组成部分,几乎所有编程语言都涉及 IO。IO 是指 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 ║
╚═══════════╝我们按顺序读取这 6 个字节,这种读取方式是输入字节流;
反过来,将 6 个字节存储到磁盘上,就是输出字节流
╔════════════╗
║ Memory ║
╚════════════╝
│0x21
│0x6f
│0x6c
│0x6c
│0x65
│0x48
▼
╔═══════════╗
║ Hard Disk ║
╚═══════════╝在 Java 中,有许多用于各种目的的 IO 类(例如读取文件的 IO 类,读取网络接口的 IO 类),我们可以简单地将它们分为输入类和输出类:
InputStream,代表输入字节流。是一个抽象类,所有输入流的超类。OuputStream,代表输出字节流。也是抽象类,是所有输出流的超类。
图片来自《Java 语言程序设计-基础篇》17.1 节
除了字节之外,我们可能还会读写字符,因此 Java 提供了 Reader 和 Writer,用来读写字符;但是,计算机中只存储 0 和 1,Reader 和 Writer 本质上也是读取字节流的;只不过他们能在读取字节的时候自动解码为 char 字符,输出字节的时候自动编码为二进制数,所以看起来就是直接读写字符了:

图片来自《Java 语言程序设计-基础篇》17.2 节
我们也可以使用 InputStream 读取字符为 byte[] 数组,然后根据编码转换为字符串。
一般情况下,使用二进制文件的效率更高:
同步 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。