IO流分类,应用(使用)场景,字节流和字符流区别?
IO流的分类?
分为字节流和字符流,字节流又分为字节输入流和字节输出流,字符流又分为字符输入流和字符输出流
输入和输出分别是指的什么?
输入流,指的是将硬盘、键盘中数据输入到内存中。
输出流,指的是将内存中的数据输出到硬盘、显示器中。
为什么要弄个输入流和输出流出来呢?
因为计算机的运行过程就是一个获取外界的数据,通过计算之后,然后输出结果的过程。这个过程中,必然是人们通过电脑外设,输入数据,计算机处理这一批数据,然后输出到显示器或者其他外设中。
字节流和字符流的区别?
不多说,直接上图:
IO流应用场景?
1、 从硬盘中读取文件内容到内存中,然后把这些数据发送到其他接口进行处理
2、 将路径A中的文件A复制到路径B中的文件B
存在的问题
实际开发中,并不知道各种流的原理、使用场景,以及优缺点,当拿到一个开发需求的时候,通常都是借鉴,而不知道为什么这样使用,所以很有必要梳理一下。
IO流常见问题
字节流相关
1、 InputStream(字节输入流)、OutputStream(字节输出流)
都是顶级父类(抽象类),其他IO流相关的类,都需要实现它们
2、FileInputStream(文件字节输入流)
基于字节流的文件操作,用于读取一个文件,打开一个实际的文件链接,并创建一个文件输出流
3、FileOutputStream(文件字节输出流)
用于将数据写入文件,创建一个向文件写数据的文件输出流
4、BufferInputStream(缓冲字节输入流)
普通的字节流增加的缓冲功能。
缓冲功能出现的原因:内存读写快,磁盘读写慢,所以二者数据传输会堵塞,所以建立缓冲区,提高文件存取效率,不管是读还是取,都是把文件先保存到缓冲区,再一次性保存到对应区域。
优点:复制所用的时间更少。
缓冲流的关闭顺序:根据依赖关系进行关闭,被依赖的后关闭,也就是先开后关。
5、BufferOutputStream(缓冲字节输出流)
与缓冲输入流作用类似
6、DataInputStream(数据过滤输入流)
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
7、DataOutputStream(数据过滤输出流)
数据输出流允许应用程序以与机器无关方式将Java基本数据类型写到底层输出流。
8、PrintStream(打印流)
PrintStream 是打印输出流,它继承于FilterOutputStream。
PrintStream 是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
与其他输出流不同,PrintStream 永远不会抛出 IOException;它产生的IOException会被自身的函数所捕获并设置错误标记, 用户可以通过 checkError() 返回错误标记,从而查看PrintStream内部是否产生了IOException。
另外,PrintStream 提供了自动flush 和 字符集设置功能。所谓自动flush,就是往PrintStream写入的数据会立刻调用flush()函数。
参考自:https://www.cnblogs.com/skywang12345/p/io_16.html
9、PrintStream和DataOutputStream异同点
相同点:都是继承与FileOutputStream,用于包装其它输出流。
不同点:
(01) PrintStream和DataOutputStream 都可以将数据格式化输出;但它们在“输出字符串”时的编码不同。
PrintStream是输出时采用的是用户指定的编码(创建PrintStream时指定的),若没有指定,则采用系统默认的字符编码。而DataOutputStream则采用的是UTF-8。
关于UTF-8的字符编码可以参考“字符编码(ASCII,Unicode和UTF-8) 和 大小端”
关于DataOutputStream的更多内容,可以参考“java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例”
(02) 它们的写入数据时的异常处理机制不同。
DataOutputStream在通过write()向“输出流”中写入数据时,若产生IOException,会抛出。
而PrintStream在通过write()向“输出流”中写入数据时,若产生IOException,则会在write()中进行捕获处理;并设置trouble标记(用于表示产生了异常)为true。用户可以通过checkError()返回trouble值,从而检查输出流中是否产生了异常。
(03) 构造函数不同
DataOutputStream的构造函数只有一个:DataOutputStream(OutputStream out)。即它只支持以输出流out作为“DataOutputStream的输出流”。
而PrintStream的构造函数有许多:和DataOutputStream一样,支持以输出流out作为“PrintStream输出流”的构造函数;还支持以“File对象”或者“String类型的文件名对象”的构造函数。
而且,在PrintStream的构造函数中,能“指定字符集”和“是否支持自动flush()操作”。
(04) 目的不同
DataOutputStream的作用是装饰其它的输出流,它和DataInputStream配合使用:允许应用程序以与机器无关的方式从底层输入流中读写java数据类型。
而PrintStream的作用虽然也是装饰其他输出流,但是它的目的不是以与机器无关的方式从底层读写java数据类型;而是为其它输出流提供打印各种数据值表示形式,使其它输出流能方便的通过print(), println()或printf()等输出各种格式的数据。
参考自:https://www.cnblogs.com/skywang12345/p/io_16.html
10、Serializable(序列化接口)
序列化接口中没有任何方法,这个接口具有标识性的意义,代表这个对象是可以序列化的。
如果对象需要被持久化到文件,或者在网络上传输对象,那么定义该对象的类,必须实现序列化接口。
为什么要实现序列化接口?
简而言之,就是对象从内存在硬盘,或者从硬盘恢复到内存,这两个过程中,都涉及到序列化。所有的对象都是在内存中的,为了防止内存吃不消,所以需要持久化到磁盘中,http请求时的报文实体类通常会用到序列化接口。
最重要的两个原因是:
1、将对象的状态保存在存储媒体中以便可以在以后重新创建出完全相同的副本;
2、按值将对象从一个应用程序域发送至另一个应用程序域。
实现serializable接口的作用是就是可以把对象存到字节流( 实现Serializable接口,在序列化时,使用ObjectOutputStream的write(object)方法将对象保存),然后可以恢复。所以你想如果你的对象没实现序列化怎么才能进行网络传输呢,要网络传输就得转为字节流,所以在分布式应用中,你就得实现序列化,如果你不需要分布式应用,那就没那个必要实现序列化。
11、ObjectInputStream(对象输入流)
12、ObjectOutputStream(对象输出流)
13、ByteArrayInputStream(字节数组输入流)
字节数组输入流在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中。
14、ByteArrayOutputStream(字节数组输出流)
字节数组流可以代替文件流,实现同样的功能,并且效率更高。
字符流相关
1、抽象类Reader和Writer
问题:
Reader和InputStream的区别?
Reader
是Java的IO库提供的另一个输入流接口。和 InputStream
的区别是,InputStream
是一个字节流,即以 byte
为单位读取,而 Reader
是一个 字符 流,即以 char
为单位读取
为什么已经有了字节流,还需要创造出字符流?
Java中一切都是字节流,没有字符流,字符只是根据编码对字节流进行翻译的结果。
Java I/O有两个
面向字节流的InputStream和OutputStream
面向字符流的Reader和Writer
Java中InputStreamReader和OutputStreamWriter是字节流向字符流解码的桥梁
字符流是由Java虚拟机将字节转换得到的
音频、视频等媒体文件用字节流比较好
涉及到字符的话使用字符流比较好
参考自:https://blog.csdn.net/qq_23864697/article/details/106506862
2、转换流InputStreamReader和OutputStreamWriter
InputStreamReader 将字节流转换为字符流。是字节流通向字符流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码,如:GBK。
OutputStreamWriter 将字符流转换为字节流。是字符流通向字节流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码,如:GBK。
3、FileReader和FileWriter
FileReader和FileInputStream类似,都是可以直接对文件进行读写,只是一个是字节,一个是字符。
但是字符流比字节流,更适合读取字符串。
适用于存取的是一个文本文件。
问题:
FileReader和FileInputStream的区别?
FileInputStream和FileReader都是用于读取文件的输入流,二者的不同在于,FileInputStream是以字节流的方式读入数据,而FileReader是以字符流的方式读取的。
如果一句话含有:英文字母,有汉字,还有标点符号。更加适合以字符的方式读取。
4、BufferedReader类(缓冲流)
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
BufferedReader的构造函数应该传入Reader类型的对象,比如FileReader。
在涉及到文件字符输入流的时候,我们使用BufferedReader中包装Reader的实例类(例如:InputStreamReader类),以提高效率。
5、PrintWriter类
和PrintStream一样,都是打印流。区别在于PrintStream是字节流,PrintWriter是字符流。