15.4.2 输入 输出流体系
15.4.2 输入 输出流体系
Java
的输入/输岀流体系提供了近40个类,这些类看上去杂乱而没有规律,但如果将其按功能进行分类,则不难发现其是非常规律的。表15.1显示了Java
输入输出流体系中常用的流分类
展开/折叠
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
抽象基类 | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
打印流 | Printstream | PrintWriter | ||
推回输入流 | PushbackInputStream | PushbackReader | ||
特殊流 | DataInputStream | DataOutputStream |
注:表15.1中的
- 粗体字标出的类代表节点流,必须直接与指定的物理节点关联;
- 斜体字标出的类代表抽象基类,无法直接创建实例。
从表15.1中可以看出,Java
的输入/输出流体系之所以如此复杂,主要是因为Java
为了实现更好的设计,它把IO
流按功能分成了许多类,而每类中又分别提供了字节流和字符流(当然有些流无法提供字节流,有些流无法提供字符流),字节流和字符流里又分别提供了输入流和输岀流两大类,所以导致整个输入输出流体系格外复杂。
其他IO流
表15.1仅仅总结了输入/输出流体系中位于Java.io
包下的流,还有一些诸如AudioInputStream
,CipherInputStream
、DeflaterInputStream
、ZipInputStream
等具有访问音频文件、加密解密、压缩/解压等功能的字节流,它们具有特殊的功能,位于JDK
的其他包下,本书不打算介绍这些特殊的IO
流。
字节流功能比字符流强大 但复杂
通常来说,字节流的功能比字符流的功能强大,因为计算机里所有的数据都是二进制的,而字节流可以处理所有的二进制文件.但问题是,如果使用字节流来处理文本文件,则需要使用合适的方式把这些字节转换成字符,这就增加了编程的复杂度。
文本内容使用字符流
所以通常有一个规则:如果进行输入/输出的内容是文本内容,则应该考虑使用字符流;
二进制内容使用字节流
如果进行输入/输岀的内容是二进制内容,则应该考虑使用字节流。
字符集
计算机的文件常被分为文本文件和二进制文件两大类。
所有能用记事本打开并看到其中字符内容的文件称为文本文件,反之则称为二进制文件。
但实质是,计算机里的所有文件都是二进制文件,文本文件只是二进制文件的一种特例,当二进制文件里的内容恰好能被正常解析成字符时,则该二进制文件就变成了文本文件。更甚至于,即使是正常的文本文件,如果打开该文件时强制使用了“错误”的字符集,例如使用EditPlus
打开刚刚生成的poem.txt
文件时使用的字符集不对,则将看到打开的poem.txt
文件内容变成了乱码。
因此,如果希望看到正常的文本文件内容,则必须在打开文件时与保存文件时使用相同的字符集(Windows
下简体中文默认使用GBK
字符集,而Linux
下简体中文默认使用UTF8
字符集)。
读写数组的节点流
表15.1中还列出了一种以数组为物理节点的节点流,
- 字节流以字节数组为节点,
- 字符流以字符数组为节点;
这种以数组为物理节点的节点流除在创建节点流对象时需要传入一个字节数组或者字符数组之外,用法上与文件节点流完全相似。
读写字符串的节点流
与此类似的是,字符流还可以使用字符串作为物理节点,用于实现从字符串读取内容,或将内容写入字符串(用StringBuffer
充当字符串)的功能。
程序 读写字符串的输入输出流
下面程序示范了使用字符串作为物理节点的字符输入/输出流的用法。
1 | import java.io.*; |
上面程序与前面使用FileReader
和FileWriter
的程序基本相似,只是在创建StringReader
和StringWriter
对象时传入的是字符串节点,而不是文件节点。由于String
是不可变的字符串对象,所以StringWriter
使用StringBuffer
作为输出节点。
管道流
表15.1中列出了4个访问管道的流:PipedInputStream
、PipedOutputStream
、PipedReader
、PipedWriter
,它们都是用于实现进程之间通信功能的,分别是字节输入流、字节输出流、字符输入流和字符输出流。
本书将在第16章介绍这4个流的用法。
缓冲流
表15.1中的4个缓冲流则增加了缓冲功能,增加缓冲功能可以提高输入、输岀的效率,增加缓冲功能后需要使用flush
才可以将缓冲区的内容写入实际的物理节点表
对象流
15.1中的对象流主要用于实现对象的序列化,本章的15.8节将系统介绍对象序列化