1、IO介绍
1.1各部分名称
I:input 输入 读取外部数据到程序内存中
O:output 输出 将程序内存中的数据输出到指定储存格式中
流:数据从源头传输到目的地这个中间的动态过程
1.2 IO操作步骤
1、确定操作 ----是输入流还是输出流
2、确定数据类型 ----是需要传输字符流还是字节流
3、找到数据源 ---- 从哪里读,写到哪里去
4、创建流对象 --- 根据上面的步骤可以知道需要一个怎样的对象
5、进行读写的过程 若是写的过程,还需要刷新
6、释放资源,关闭流
2、IO的操作
2.1数据分类
2.1.1流处理的数据单元
字符:传输的是纯文本信息,用字符接收 char
字节:传输的类型有很多,可以是文本、图片、音频、视频。以字节的形式传输
2.1.2流的功能分类
节点流:直接从源头读写数据,称为节点流
处理流:不直接连接到数据源或目的地,而是"连接"在已存在的流上,通过对数据的处理为程序提供更为强大的读写功能
根据流的数据单元和功能可以简单的分为这四种情况
2.2节点流
2.2.1字符节点流
直接从源头,以字符的形式传输数据 以读数据为例
// 找到数据源
File file = new File("E:\\javayuanwenjian\\Reborn\\IO1.txt");
// 创建一个读数据的对象,引用刚刚找到的数据源
FileReader fr = new FileReader(file);//这里表明从当前地址去找内容
// 现在开始进行读数据
fr.read();
// 关闭流
fr.close();
在使用字符节点流对数据进行处理时,是一个一个数据进行读取的,读取速度很慢,而且不知道什么时候能读完,这里需要一个控制方法 ------- `fr.read() 返回的是一个int类型,表明读取的实际内容,若读取的数据后面没有内容时,返回的结果为-1。所以这里可以进行控制判断。改进的代码为:
//需要用一个整形变量来控制是否继续打印
int num = 0;
// 注:返回的是ASCII字节码 若给一个char数组,read方法会把读取的内容放在char数组里面
while((num=fr.read())!=-1){
System.out.print((char)num); // 返回的是ASCII字节码,所以这里需要进行一个强转
}
// 关闭流
fr.close();
虽然是一个一个的读取,但我们也可以用一个临时的字符数组来接收数据,然后一次性传输
// 定义一个整形变量 控制循环 再定义一个字符数组接收
int count = 0;
char[] cs = new char[3]; // 数字是接收的个数
while((count = fr.read(cs))!=-1){ // 这里就加上了数组,读取的内容会放在cs数组里
System.out.print(Arrays.toString(cs)); // 打印出数据,但这打印出的内容是数组格式
String str = new String(cs,0,count,"UTF8"); // 把cs数组的内容以字符串的形式进行打印,后面0表示偏移量,count表示打印的个数,最后是转换时数组的文本格式
System.out.print(str);
}
// 最后关闭流
fr.close();
2.2.2字节节点流
字节节点流是直接从源头,以字节的形式传输数据的
同样的也需要找到一个位置 这里以传输数据为例
// 找到数据源
File file = new File("E:\\javayuanwenjian\\Reborn\\W.txt");
// 创建一个写数据的对象,引用刚刚找到的数据源
FileOutputStream fos = new FileOutputStream(file); //这里表明的是把写好的数据放到我们给定的地址中去,若文件不存在,则会创建一个该文件
byte[] bt = new byte[]{3,5,8,9,7,6,4}; // 字节流 需要的是字节数组
//开始读写数据进去
fos.write(bt); // 括号里需要参数,可以是整数类型或者字节数组。所以需要先定义一个整形变量或者字节数组
// 这的输出内容只能是整数类型或者字节数组 若要录入非字节数组内容的话,还需要把格式转化位字节数组的格式
// String str = "abcdef";
// byte[] bs = str.getBytes();
// 刷新书写的内容
fos.flush();
// 关闭流
fos.close();
2.3处理流
处理流可以是加强传输数据的速度,可以是加多传输数据的类型,也可以是让字符字节进行转换。它们必须要套在节点流上传输数据
2.3.1缓冲处理流
缓冲理解:创建内部缓冲区数组,用一个数组来接收读写数据。导致起读写效率大大提升。
根据数据单位可分为:
缓冲字符流:BufferedReader和BufferedWriter
缓冲字节流:BufferedInputStream和BufferedOutputStream
缓冲字符流和节点流大同小异,但在声明一个缓冲处理流后,最后还是需要节点流来进行实现
注:缓冲处理流不能进行多态
2.3.1.1缓冲字符流
// 创建一个缓冲字符输入流
// 从最里层往外理解:找到一个目标文件地址-->创建一个文件输入对象-->创建一个缓冲字符输入对象
BufferedReader br = new BufferedReader(new FileReader(new File("E:\\javayuanwenjian\\Reborn\\IO1.txt")));
//在读取数据前,要先声明一个计数器--用于控制循环以及打印数据,声明一个字符数组,用于临时储存数据
int num = 0;
char[] cs = new char[6]; // 以6个字符进行接收
// 开始进行读取数据,让数据读取完,进行循环。
while((num = br.read(cs))!=-1){
System.out.print(new String(cs,0,num))
}
System.out.println();
// 关闭流
br.close()
// 创建一个缓冲字符输出流
// 从里层往外:找到一个目标文件地址进行录入-->创建一个文件输出对象-->创建一个缓冲字符输出对象
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("E:\\javayuanwenjian\\Reborn\\IO2.txt")));
// 因为需要用到的是缓冲字符 所以一定需要一个char类型的数组,用来接收数据
char[] cw = new char[6];//设定每次接收的字符,因为这里是直接输入内容。不需要这个字符数组
// 输入内容
String str = "张子枫你好啊";
// 录入
bw.write(str);
// 刷新
bw.flush();
// 关闭
bw.close();
字符的输入和输出相较于字节要简便很多,而且字符的输入输出是不能去改写文本的格式的,但如果文本格式不同时,就要考虑使用字节输入输出,去更改相匹配的格式。
// 创建一个缓冲字节输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("E:\\javayuanwenjian\\Reborn\\IO2.txt")));
// 声明计数器
int num = 0;
// 声明字节数组
byte[] bs = new byte[1024];
// 循环读取数据
while((num = bis.read(bs))!=-1){
new String(bs,0,num); // 直接把字节数组转化成字符串,0是偏移量,num是转化个数
}
// 关闭流
bs.close();
2.3.1.2缓冲字节流
字节输出流在进行数据输出的时候要注意到:若传送的数据是字符串,需要把字符串转成字节数组,然后再进行输出。不然输出的数据会是乱码,另:数据的文本格式要和输出的文本格式保持一致。
// 用缓冲字节输出流录入字符串
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("E:\\javayuanwenjian\\Reborn\\IO2.txt")));
// 声明一个字符串
String str = "abcdefghijk";
// 把这个字符串转换为字节数组
byte[] bt = str.getBytes();
// 开始读取
bos.write(bt);
// 刷新
bos.flush();
// 关闭流
bos.close();
2.3.2 转换处理流
提供了字节和字符之间的转换 实际上:把字节流转换为字符流
类:
InputStreamReader 转换输入流
OutputStreamWriter 转换输出流
2.3.2.1转换输入流
转换输入流 是把字节流转换为字符流 所以InputStreamReader 本质上还是可以看成是一个字符流。
所以这里还是用字符去进行读取的,创建临时储存数据应该用字符数组。
这是支持多态的,但是不能使用readLine()方法
// 读取文件
File file = new File("E:\\javayuanwenjian\\Reborn\\IO2.txt");
// 先创建一个字节输出流
InputStream is = new FileInputStream(file);
// 对流进行转换
Reader isr = new InputStreamReader(is,"UTF8"); //这里可以设置格式,这个格式是表示字节和字符之间的转换会以怎样的格式进行
// 准备空间和计数器
int num = 0;
char[] cs = new char[6];
// 循环读取数据
while((num = isr.read(cs))!=-1){
System.out.print(new String(cs,0,num));
}
System.out.println();
// 关闭流
isr.close();
2.3.2.2转换输出流
转换输出流是把字节流转换为字符流,OutputStreamWriter 实际上是一个输出字符流 使用方式和输入流大同小异,注意在输出时刷新。
// 创建文件
File file = new File("E:\\javayuanwenjian\\Reborn\\IO2.txt");
// 创建一个输出字节流,选择把数据输出的位置
OutputStream os = new FileOutputStream(file);
// 把输出字节流转换为输出字符流
Writer osw = new OutputStreamWriter(os,"UTF8");
String str = "bed bed good good good 挺好的 世界很好";
osw.write(str); //这里虽然有用字节流,但是实际上还是用字符流在进行读取,所以可以直接读取汉字
// 刷新
osw.flush();
// 关闭
osw.close();
2.4数据处理流
如果把某些特定的数据类型输入在储存文件中,输出时可能就不是自己想要的类型。这个时候需要用到我们的数据处理流。数据处理流的作用是保留数据的类型,但必须是先写后读。而且输入顺序和输出顺序必须保持一致。类分别为:DataInputStream 数据输入流 DataOutputStream 数据输出流 是字节流的子类。
2.4.1数据输出流 ---写
// 目标文件地址
File file = new File("E:\\javayuanwenjian\\Reborn\\IO3.txt");
// 创建一个数据输出流
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
// 定义一个成员变量,并把他输出在文件上
int i = 1;
// 输出这个i
dos.writeInt(i);
// 刷新
dos.flush();
// 关闭流
dos.close();
2.4.2数据输入流 ---读
// 创建一个数据输入流 目标文件地址直接
DataInputStream dis = new DataInputStream(new FileInputStream("E:\\javayuanwenjian\\Reborn\\IO3.txt"));
// 这里不能直接去接收,应该按照类型来接收
dis.readInt();
// 关闭流
dis.close();
好处:可以保留录入的数据类型。
缺点:在输出的时候一定要按照相对应的数据类型输出,否则不会保留格式。
2.5对象处理流
2.5.1序列化
序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
序列化步骤:
1、首先需要一个类实现了Serializable接口
2、创建一个ObjectOutputStream
3、调用ObjectOutputStream对象的writeObject(对象)方法输出可序列化对象
4、写一次,需要刷新一次
2.5.2对象处理流
class Student implements Serializable{
private static final long serialVersionUID = -5187227321050332651L;// 序列号
// 有了这个序列号以后,在接收读取文件时,主要看序列号是否有发生改变
// 这个类的属性增加或者改变不会影响计算机的判断
private String name;
private Integer age;
public String toString(){
return "Student{"+"name="+name+'\''+",age="+age'}';}
public Student(){}
public Student(String name,Integer age){
this.name = name;
this.age = age;
}
}
public class ObjectStreamTest{
public static void main(String[] args){
//录入一个学生对象 首先需要创建一个对象输出流
ObjectOutputStream oos = new ObjectOutpurStream(new FileOutputStream("E\\src\\student.txt"))
// 实例化一个学生对象
Student s1 = new Student("张子枫",18);
// 录入该学生对象
oos.writeObject(s1);
// 刷新
oos.flush();
//关闭对象输出流
oos.close();
}
}
对象输入流 方式一样
// 创建一个对象输入流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E\\src\\student"));
//这里要注意,我们是用Object直接去读取的,读取的对象会是一个Object对象,但内容本身是一个Student。输出内容也是Student 可以用instanceof 进行判定,然后再强转。也可以不用管,直接接收结果
Object o = new Object;
o = ois.readObject();
// 关闭流
ois.close();