IO第二回:认识IO流
标签: IO流
在讲完File类后,我们回到I/O流的框架
“流”的概念
我们最开始认识到:水流来表示水的传输,电流表示电的传输,人流表示…
流,是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO原理
IO流,也就是输入/输出流,用来处理设备之间的数据传输。Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
这里面的输入和输出,读和写,都是站在程序的角度上来考虑,我即程序:
- 输入 input/Reader:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- 输出 output/Writer:将程序(内存)数据输出到磁盘、光盘等存储设备中
IO流分类
Java的IO流是一个大家族,共涉及40多个类。但实际上非常规则,都是从如下4个抽象基类派生的。
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
从分类上就将:
- 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流
下面进行详解
字节流
字节流以字节(8bit)为单位,能处理所有类型的数据(如图片、avi等)。
1. 输入字节流InputStream
下面,是以字节为单位的输入流的框架图。
从中,我们可以看出:
InputStream 是以字节为单位的输入流的超类。InputStream提供了read()接口从输入流中读取字节数据。
ByteArrayInputStream 是字节数组输入流。它包含一个内部缓冲区,该缓冲区包含从流中读取的字节;通俗点说,它的内部缓冲区就是一个字节数组,而ByteArrayInputStream本质就是通过字节数组来实现的。
PipedInputStream 是管道输入流,它和PipedOutputStream一起使用,能实现多线程间的管道通信。
FilterInputStream 是过滤输入流。它是DataInputStream和BufferedInputStream的超类。
DataInputStream 是数据输入流。它是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。
BufferedInputStream 是缓冲输入流。它的作用是为另一个输入流添加缓冲功能。
File 虽然在io包中定义,但是它的超类是Object,而不是InputStream。
FileDescriptor 是“文件描述符”。它可以被用来表示开放文件、开放套接字等。
FileInputStream 是文件输入流。它通常用于对文件进行读取操作。
ObjectInputStream 是对象输入流。它和ObjectOutputStream一起,用来提供对“基本数据或对象”的持久存储。
2. 字节输出流OutputStream
下面,是以字节为单位的输出流的框架图。
从中,我们可以看出。以字节为单位的输出流的公共父类是OutputStream:
OutputStream 是以字节为单位的输出流的超类。OutputStream提供了write()接口从输出流中读取字节数据。
ByteArrayOutputStream 是字节数组输出流。写入ByteArrayOutputStream的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() 和 toString() 获取数据。
PipedOutputStream 是管道输出流,它和PipedInputStream一起使用,能实现多线程间的管道通信。
FilterOutputStream 是过滤输出流。它是DataOutputStream,BufferedOutputStream和PrintStream的超类。
DataOutputStream 是数据输出流。它是用来装饰其它输出流,它“允许应用程序以与机器无关方式向底层写入基本 Java 数据类型”。
BufferedOutputStream 是缓冲输出流。它的作用是为另一个输出流添加缓冲功能。
PrintStream 是打印输出流。它是用来装饰其它输出流,能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
FileOutputStream 是文件输出流。它通常用于向文件进行写入操作。
ObjectOutputStream 是对象输出流。它和ObjectInputStream一起,用来提供对“基本数据或对象”的持久存储。
字符流
字符流以字符为单位,根据码表映射字符,一次可能读多个字节。字符流只能处理字符类型的数据。只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流
1. 字符输入流Reader
下面,是以字符为单位的输入流的框架图。
从中,我们可以看出。以字符为单位的输入流的公共父类是Reader:
Reader 是以字符为单位的输入流的超类。它提供了read()接口来取字符数据。
CharArrayReader 是字符数组输入流。它用于读取字符数组,它继承于Reader。操作的数据是以字符为单位!
PipedReader 是字符类型的管道输入流。它和PipedWriter一起是可以通过管道进行线程间的通讯。在使用管道通信时,必须将PipedWriter和PipedReader配套使用。
FilterReader 是字符类型的过滤输入流。
BufferedReader 是字符缓冲输入流。它的作用是为另一个输入流添加缓冲功能。
InputStreamReader 是字节转字符的输入流。它是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
FileReader 是字符类型的文件输入流。它通常用于对文件进行读取操作。
2. 字符输出流Writer
下面,是以字符为单位的输出流的框架图。
从中,我们可以看出。以字符为单位的输入流的公共父类是Writer。
Writer 是以字符为单位的输出流的超类。它提供了write()接口往其中写入数据。
CharArrayWriter 是字符数组输出流。它用于读取字符数组,它继承于Writer。操作的数据是以字符为单位!
PipedWriter 是字符类型的管道输出流。它和PipedReader一起是可以通过管道进行线程间的通讯。在使用管道通信时,必须将PipedWriter和PipedWriter配套使用。
FilterWriter 是字符类型的过滤输出流。
BufferedWriter 是字符缓冲输出流。它的作用是为另一个输出流添加缓冲功能。
OutputStreamWriter 是字节转字符的输出流。它是字节流通向字符流的桥梁:它使用指定的 charset 将字节转换为字符并写入。
FileWriter 是字符类型的文件输出流。它通常用于对文件进行读取操作。
PrintWriter 是字符类型的打印输出流。它是用来装饰其它输出流,能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
字节流转换为字符流
在java中,字节流能转换为字符流,下面是它们的转换关系图。
从中,我们可以看出。
FileReader继承于InputStreamReader,而InputStreamReader依赖于InputStream。具体表现在InputStreamReader的构造函数是以InputStream为参数。我们传入InputStream,在InputStreamReader内部通过转码,将字节转换成字符。
FileWriter继承于OutputStreamWriter,而OutputStreamWriter依赖于OutputStream。具体表现在OutputStreamWriter的构造函数是以OutputStream为参数。我们传入OutputStream,在OutputStreamWriter内部通过转码,将字节转换成字符。
节点流和处理流
节点流和处理流是两个流的概念:
- 节点流可以从一个特定的数据源读写数据,直接作用在文件上
- 处理流是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
举个例子:
流的关闭顺序
- 一般情况下是:先打开的后关闭,后打开的先关闭
- 另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b。例如,处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b
- 可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。
注意:
- 如果将节点流关闭以后再关闭处理流,会抛出IO异常。
- 如果关闭了处理流,再关闭与之相关的节点流,也可能出现IO异常。(hadoop编程文件流操作中遇到了。)