何时使用字符流:如果操作的是文本数据时,这时候就应该使用字符流。
何时使用字节流:如果操作的是非文本数据时,这时候则应该使用字节流。非文本:图片、音频、视频、word
InputStream
如果需要操作文件的内容数据,就需要IO流技术。
IO流类别:
- 流向划分:
输出流
输入流
输入流输出流的判断标准:
以当前程序作为参照物,数据如果流出,则使用输出流;如果数据是流入,则使用输入流。 - 处理的单位
字节流:字节流就是用于读取文件的字节数据的,读取到的数据不会经过任何的处理。
字符流:读取到的字节数据还会帮你转换成你看的懂的字符数据,读取的是以子符为单位的数据。字符流=字节流+解码
输入字节流:
-----------|InputStream 抽象类 输入字节流的基类
----------------|FileInputStream 读取文件数据的输入字节流
使用FileInputStream读取文件数据:
每读取文件中三个字节就存储到buf数组中然后输出一次,然后再读取文件中的三个字节存储到buf数组中,再输出一次,重复这样,到读完文件中全部的内容。
OutputStream
输出字节流:
-----------| OutputStream 抽象类,所有输出字节流的父类
-----------------|FileOutputStream 向文件输出数据的输出字节流
使用FileOutputStream步骤:
FileOutputStream要注意的细节:
- new FileOutputStream的时候,如果目标文件不存在,那么会先创建目标文件,然后写入。
- new FileOutputStream(file)如果目标文件已经存在,那么会先清空目标文件的数据,然后再写入新的数据。
- 写入数据的时候如果需要以追加的形式写入,那么需要使用new FileOutputStream(file,true)这个构造函数。
- 使用write(int b)方法的时候,虽然参数接受的是一个int类型的数据,但是实际上只会把数据的低八位写出,其他24位丢弃。
IO异常处理
public static void main(String[] args) {
input();
}
public static void input() {
FileInputStream fileInput=null;
try {
File file= new File("D:\\c.txt");
fileInput= new FileInputStream(file);
byte [] b=new byte[1024];
int length=0;
while((length=fileInput.read(b))!=-1){
System.out.println(new String(b,0,length));
}
} catch (IOException e) {
System.out.println("读取失败");
throw new RuntimeException(e);//将编译异常包装成运行异常(糖衣炮弹),这样调用者就不用声明抛出异常了
} finally{
try {
if(fileInput!=null){
fileInput.close();
System.out.println("关闭成功");
}
} catch (IOException e) {
System.out.println("关闭失败");
throw new RuntimeException(e);
}
}
}
缓冲IO字节流
使用FileInputStream读取文件数据的时侯如何读取效率最高?
使用字节数组作为缓冲区读取的效率是最高的。
我们知到使用缓冲字节数组读取文件的效率最高,sun也知道使用缓冲数组读取的效率高,这时候sun为了方便我们工作,编写了一个缓冲输入字节流给我们去使用。
缓冲输入字节流的作用:提高我们读取文件数据的效率。
输入字节流的体系:
-----------------|InputStream 抽象类 所用输入字节流的基类
------------------------|FileinputStream 读取文件数据的输入字节流
------------------------|BufferedInputStream 缓冲输入字节流 该类的本质其实只是在内部维护了一个8kb的字节数组而已。 主要是为了提高我们的读取文件的效率。
凡是缓冲流都没有读写文件的能力。
BufferedInputStream注意的事项:
1. BufferedInputStream的close方法实际上关闭的就是你传递进去的FileInputStream对象。
疑问:BufferedInputStream的read方法每次只是读取一个字节的数据,FileInputStream的read方法每次也是读取一个字节的数据,那么为什么说BufferedInputStream提高了读取的效率呢?
一个是从内从读取数据,一个是从硬盘读取数据。
疑问:为什么创建BufferedInputStream对象需要传入一个InputStream的对象呢?
BufferedInputStream没有读取文件数据的能力,但是又要读取文件的数据,这时候只能依赖一个具备读取文件数据能力的对象。
缓冲输出字节流:为了提高写文件的效率。
示例:
--------------|OutputStream 抽象类,所有输出字节流的基类。
---------------------|FileOutputStream 向文件写入数据的输出字节流对象。
---------------------|BufferdOutputStream 缓冲输出字节流,为了提高写文件数据的效率。
BufferdOutputStream注意的事项:
- 使用BufferedOutputStream的write方法时,数据其实是写入了BufferedOutputStream内部维护的字节数组中,只用你调用了BufferedOutputStream的close方法或者是flush方法后数据才会真正的写到硬盘上去或者内部维护的字节数组已经存储满了数据了,这是侯数据也会写到硬盘上去。
- BufferedOutputStream的close方法实际上关闭的就是你传入的OutputStream对象;
示例:
字符流
字符流:读取的数据是以字符为单位的,会把读取到的字节数据转换成我们看得懂的字符。 字符流=字节流+编码(解码)
输入字符流:
------------------|Reader 抽象类 所有输入字符流的基类。
------------------------|FileReader 读取文件数据的输入字符流。
示例:
输出字符流:
------------------|Writer 抽象类 输出字符流的基类。
--------------------------|fileWriter 向文件写出数据输出字符流。
示例:
FileWriter要注意的事项:
- new FileWriter(file)的时候,如果目标文件不存在,那么会先创建目标文件对象,如果目标文件已经存在了,那么则不再重新创建。
- 使用new FileWriter(file)这个构造方法的时候,默认是会先清空文本的数据,然后再写入新的数据。如果需要追加数据则需要使用new FileWriter(file,true)这个构造方法。
使用FileWriter的writer方法的时候,数据是写入了FileWriter内部维护的字符数组中,如果需要把数据真正的写道硬盘上去,需要调用flush方法或者是close方法,或者是内部维护的字符数组已经满了,这时候也会写到硬盘上。
缓冲输入字符流
输入字符流的缓冲流:
----------------------------|Reader 抽象类,所有输入字符流的基类
-----------------------------------|FileReader 读取文件字符数据的输入字符流。
-----------------------------------|BufferedReader 缓冲输入字符流,该类出现的目的:提高读取文件字符数据的效率,对FileReader的功能进行了拓展----readLine()。读一行
缓冲输出字符流
缓冲输出字符流:
---------------|Writer 抽象类 所有输出字符流的基类。
---------------------|FileWriter 向文件输出数据的输出字符流。
---------------------|BufferedWriter 缓冲输出字符流,目的:为了提高写文件数据的效率以及拓展FileWriter的功能----newLine()。
示例:
对象的输入输出流对象
ObjectOutputStream(对象的输出流对象):该类主要是用于把对象数据写出到文件上的。
ObjectOutputStream要注意的事项:
- 使用ObjecOutputStream的writeObject方法的时候,只能写出实现了Serializable接口的对象。Serializable接口没有任何的方法,这种接口我们称作为标志接口。
- 对象反系列化的时候创建对象是不会调用构造方法的。
- 我们把对象写道文件上的时候,文件除了记录对象的一些信息以外,还记录了class的版本号(serialVersionUID),这个版本号是通过一个类的类名、包名、工程名、成员一起算出的一个id号。
- 再反序列化的时候,jvm会使用本地class文件算出一个id号与文件记录的id号进行对比,如果不一致,反序列化失败。
- 如果一个类的成员可能在后期会发生改动,那么可以在序列化之前就指定一个serialVersionUID,如果一个类一经指定了一个serialVersionUID,那么java虚拟机则不会再计算该class文件的serialVersionUID了。
- 如果一个类的某些成员不想被序列化到硬盘上,可以使用关键字transient修饰。
- 如果一个类的内部维护了另外一个类对象,那么另外一个类也必须要实现Serializable接口。
对象的序列化:把对象写道文件上叫做对象的序列化。
对象的反序列化:对象的反序列化就是读取硬盘中的对象到内存中。
Properties配置文件类
Properties—》配置文件类 属于Map集合体系
Properties的作用:
- 生成配置文件。
- 读取配置。
Properties要注意的事项: - 往Proterties添加数据的时候,千万不要添加非字符串类型的数据,如果添加了非字符串类型的数据,那么properties的处理方法就是进行强制类型转换,转换报错。
- 如果properties的数据出现了中文字符,那么使用store方法时,千万不要使用字节流,如果使用了字节流,那么默认使用iso8859-1码表进行保存,如果出了中文数据建议使用字符流。
- 如果修改了proterties里面的数据,一定要重新生成一个配置文件(所以要先加载配置文件,才能实现追加数据)。
PrintStream打印流
我们使用字节流或者字符流写出int类型数据的时候会比较麻烦,因为我们需要把这些数据转换成字符串然后我们才能写出去。
打印流的好处:
- 打印流可以打印任何类型的数据。
- 打印流打印任意类型数据之前,会先把数据转成字符串然后再打印出去。
作用一:
作用二:
编码与解码
编码与解码要注意的事项:
- 我们一般都会让编码与解码使用同样的码表,这样子可以避免出现乱码问题。
- 英文在每个码表中都是兼容的。
转换流
转换流:
InputStreamReader : InputStreamReader是字节流通向字符流的桥梁。
OutputStreamWriter 输出字节流的转换流。输出字节流转成输出字符流。
转换流的作用:
- 可以把字节流转换成字符流。
- 可以指定任意的码表进行读写数据。
示例:
输入字节流换成输入字符流:
输出字节流转换成输出字符流:
指定码表进行写数据: