JavaSE01_Day04(中下)-缓冲输入输出流、对象流、字符流
一、缓冲输入流和缓冲输出流
1.1 BufferedInputStream缓冲字节输入流工作原理
文件输入流对于文件中的数据进行读取时,是以字节为单位进行读写的,会因为频繁进行读取操作,而降低读取效率,这也就是读取效率慢的原因。如果搭配缓冲字节输入流,当进行读取数据时,仍然是以字节为单位进行读取数据,但是缓冲字节输入流中维护了一个缓冲区(字节数组),使用该流进行读取字节时,会尽可能的多的一次性读取若干字节,然后存储到缓冲区中,然后按照读取的需要的字节量进行字节的返回,直至缓冲区的数据全部被读取完毕,再进行读取若干字节到缓冲区中,这样操作会反复执行多次,就可以减少读取的次数,从而提高读取的效率。
1.2 BufferedOutputStream缓冲字节输出流工作原理
缓冲字节输出流的工作原理和上面的缓冲字节输入流工作原理类似,在向磁盘中进行写出数据操作时,增加写出次数会降低写出的效率,所以我们可以采用缓冲字节输出流进行一次性批量的写出若干数据,进而减少读写的次数,提高读写效率。当搭配缓冲字节输出流进行使用后,内部维护了一个缓冲区(字节数组),可以一次性批量写出若干数据,从而减少写出次数,进而提高写出效率。当进行写出的时候,会先将数据存储到缓冲区中,当缓冲区满了以后,会一次性全部进行写出操作。如果希望缓冲区存储的数据没有满的时候就进行数据的全部写出操作,此时需要手动去调用flush()
方法强制输出。
package cn.tedu.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* 使用缓冲字节流完成对音频文件的复制案例
* @author cjn
*
*/
public class BOS_BIS_Copy {
public static void main(String[] args) throws Exception {
/*
* 1.读取音频文件
* 文件流是一个低级流,低级流往往对数据源明确,创建缓冲字节输入流(高级流)以后,
* 需要在创建对象的时候,将低级流对象作为创建构造器的参数进行传递(流连接)
*/
//创建文件字节输入流(低级流)对象
FileInputStream fis = new FileInputStream("G_E_M_ 邓紫棋 - 句号.mp3");
//创建缓冲字节输入流(高级流)对象
BufferedInputStream bis = new BufferedInputStream(fis);
/*
* 2.写出音频文件
*/
//创建文件字节输入流(低级流)对象
FileOutputStream fos = new FileOutputStream("G_E_M_ 邓紫棋 - 句号copy.mp3");
//创建缓冲字节输出流(低级流)对象
BufferedOutputStream bos = new BufferedOutputStream(fos);
//3.读写数据
int len = 0;//实际读取字节量的大小
while ((len=bis.read()) != -1) {//未读取到末尾
bos.write(len);//写出数据
}
System.out.println("复制音频文件完成!!!");
//4.关闭资源
bis.close();
bos.close();
}
}
1.3 BufferedOutputStream提供的flush方法
使用缓冲字节输出流可以提高对于文件的读写效率,但是在写出数据的时候会存在数据的实时性相对较差的情况。在数据存储缓冲区的时候也是有时间的,并且需要将缓冲区的数据全部存满以后才会进行写出。如果是希望实时的去完成数据的写出,可以手动的调用flush
方法。在close
方法中已经提供了在关闭资源的时候,强制输出缓冲区的数据。
package cn.tedu.io;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
/**
* 缓冲字节输出流写出数据的缓冲区案例演示
* @author cjn
*
*/
public class BOS_Flush {
public static void main(String[] args) throws Exception {
//1.使用流连接
//创建文件字节输出流(低级流)对象
FileOutputStream fos = new FileOutputStream("bao.txt");
//创建缓冲字节输出流(高级流)对象
BufferedOutputStream bos = new BufferedOutputStream(fos);
//2.准备存储的字符串数据
String str = "今天天气不错,风和日丽的!!!";
//3.将字符串内容转化为字节序列
byte[] data = str.getBytes("utf-8");
//4.写出数据
bos.write(data);
//bos.flush();//此处写不写结果都一样,就人眼而言看不出来差别,但计算机能识别
System.out.println("写出完毕!!!");
//5.关闭资源
bos.close();
}
}
二、对象流
2.1 定义:
对象流是高级流,也可以称之为是处理流,可以对Java中任何的对象进行读写操作。
2.2 应用场景:
原本Java对象是存储在内存中的,有时往往需要将Java对象保存到外部设备中,再有时我们也需要将对象传输到另一台计算机等这样的操作,可以使用对象流。
2.3 对象序列化
将Java对象转换为字节序列,这个过程就称之为对象的序列化。相反而言,有字节序列需要进行转换为Java对象,这个过程就称之为反序列化。
2.4 代码业务场景要求:
-
定义一个Person类,类中包含姓名、性别、年龄、爱好属性(每个人的爱好都不止一个,这个爱好属性为字符串数组类型)。
-
将Person对象进行序列化到文件中,文件名为person.obj。
-
将Person对象从person.obj文件中反序列出来,并打印输出到程序的控制台中。
2.5 将对象进行序列化要求:
-
该对象需要实现一个序列化接口
Serializable
,实现该接口以后,不需要添加任何该接口重写的方法。 -
在类中需要提供一个
serialVersionUID
。
Person:
package cn.tedu.io;
import java.io.Serializable;
import java.util.Arrays;
public class Person implements Serializable{
/**
* 1.Person类中添加姓名、性别、年龄、爱好:属性
* 2.生成set和get方法:设置或获取属性
* 3.添加构造器:初始化属性
* 4.添加toString方法:重写该方法后,输出对象时直接输出对象内容
* 5.添加equals方法:重写该方法后,比较时直接比较对象内容而非地址值
* 6.实现序列化接口:Person类实现Serializable接口
* 7.添加serialVersionUID
*/
private static final long serialVersionUID = 1L;
private String name;
private char gender;
private int age;
private String[] hobby;
public Person() {}
public Person(String name, char gender, int age, String[] hobby) {
super();
this.name = name;
this.gender = gender;
this.age = age;
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String[] getHobby() {
return hobby;
}
public void setHobby(String[] hobby) {
this.hobby = hobby;
}