流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。Java
的 I/O
是建立在流(Stream
)之上的,输入流读取数据,输出流写入数据。流是同步的,也就是说当请求流读一段数据时,阻塞等待直到有数据。Java
还支持使用通道和缓冲区的非阻塞 I/O
(NIO
),暂不讨论。
流的分类
按流向分类
- 输入流: 程序可以从中读取数据的流
- 输出流: 程序能向其中写入数据的流
按数据传输单位分类
- 字节流
以字节(8 位二进制)为单位进行处理。主要用于读写诸如图像或声音的二进制数据。 - 字符流
字符流中的对象融合了编码表,以字符为单位,根据码表映射字符,一次可能读多个字节,字符流只能处理字符文本类型的数据。字符流是对字节流进行了封装,方便操作,在最底层所有的输入输出都是字节形式的。后缀是Stream
是字节流,而后缀是Reader, Writer
是字符流。
按功能分类
- 节点流
从特定的地方读写的流类,如磁盘或者一块内存区域,直接与数据源相连读入或读出。 - 处理流
使用节点流作为输入或输出,处理流是使用一个已经存在的输入流或者输出流连接创建的。
流操作的类或接口
基本类和接口
File
:文件类RandomAccessFile
:随机存取文件类InputStream
:字节输入流OutputStream
:字节输出流Reader
:字符输入流Writer
:字符输出流
流类的结构图
各个类基本介绍:
- 文件操作
FileInputStream, FileOutputStream, FileReader, FileWriter
- 管道操作
PipedInputStream, PipedOutStream, PipedReader, PipedWriter
,PipedInputStream
的实例必须要和PipedOutputStream
的实例共同使用,共同完成管道的读取写入操作,主要用于线程操作。 - 字节/字符数组
ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter
,在内存中开辟了一个字节或字符数组。 - 缓冲流
BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
,是带缓冲区的处理流。缓冲区的作用的主要目的是:避免每次和硬盘打交道,提高数据访问的效率。 - 转化流
InputStreamReader, OutputStreamWriter
,把字节转化成字符。 - 过滤流
FilterInputStream, FileOutputStream
,装饰模式,用来装饰基本流。 - 数据流
DataInputStream, DataOutputStream
,字节流只能单字节的输出,但是long
类型(8 字节)或float
类型(4 字节)是多字节的,需要逐字节或者转换为字符串输出,数据流提供了这个解决方案。数据流可以用二进制格式读写Java
的基本数据类型和字符串。 - 打印流
PrintStream, PrintWriter
,一般是打印到控制台。 - 对象流
ObjectInputStream, ObjectOutputStream
,把封装的对象直接输出,而不是一个个在转换成字符串再输出。 - 序列化流
SequenceInputStream
,把对象序列化,直接转换成二进制,写入介质中。
流分类表格
Java IO
是采用的是装饰模式,即采用处理流来包装节点流的方式,来达到代码通用性- 处理流和节点流的区分方法,节点流在新建时需要一个数据源(文件、网络)作为参数,而处理流需要一个节点流作为参数
- 处理流的作用就是提高代码通用性,编写代码的便捷性,提高性能
- 节点流都是对应抽象基类的实现类,它们都实现了抽象基类的基础读写方法
常见输入输出流
Java
提供的基本输入输出流中,字节流类为 java.io.InputStream/OutputStream
,字符流类为 java.io.Reader/Writer
,它们都是抽象类,提供了读写数据需要的基本方法。
字节流
1 | public abstract class InputStream implements Closeable { |
字符流
1 | public abstract class Reader implements Readable, Closeable { |
字节字符转换流
1 | public class InputStreamReader extends Reader { |
字节字符转换,需要在构造方法中指定编解码类型,如果不指定使用平台默认。
InputStreamReader
可对读取到的字节数据经过指定编码转换成字符。OutputStreamWriter
可对读取到的字符数据经过指定编码转换成字节。
过滤流
过滤流是装饰模式中的装饰者,基本输入输出流是被装饰者,过滤流用来装饰其他基本流。过滤器流以链的形式进行连接,通过构造方法把流绑定,这种连接是永久的,过滤器无法无法与流断开连接。链中除了最后一个过滤器外,不能从中间流读取数据。
1 | public class FilterInputStream extends InputStream { |
缓冲流
不带缓冲的操作,每读一个字节就要写入一个字节。由于涉及磁盘的 IO
操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
缓冲流将写入的数据存储在缓冲区中,直到缓冲区满或者刷新输出流,然后将数据一次全部写入低层输出流。
1 | public class BufferedInputStream extends FilterInputStream { |
参数解析:
InputStream/OutputStream/Reader/Writer
底层字节/字符流,可以从中读取或写入未缓冲的数据。字符缓冲流中的参数,通常会使用字节字符转换流作为参数InputStreamReader/OutputStreamWriter
。size
缓冲区的大小,默认为 8192 个字节。
参考文档
Java
源码- Java IO流学习总结
- Java IO流分析整理