一,介绍IO流:
IO流:是指在计算机程序中用于处理输入和输出的数据流。
**注:**进行读写文件,读写的对象可以是文件,可以是网页内容。
I: ----input 输入:从程序外到程序里。把文档信息读到程序。
O :---output 输出:信息从程序里输送到程序外。
流:(管道):输送方法,信息在程序和程序外进行的交流。
二,IO流分类:
共6种:
根据流方向: 输入流 输出流。
根据流承载信息的大小: 字节流:(1个字节8位) 字符流:两个字节(16位能处理汉字)
根据流的功能:节点流:一根管处理某种数据对应的流 处理流:管套管嵌套处理。
补: 节点流和处理流区别:
1字符流和字节流都是节点流(只有输入输出功能) 处理流(有其它功能)
2节点流直接连接数据源,处理流连接节点流对象。
三,Io流使用举例:
1字节输入流读取文本文件:
public static void main(String[] args) throw IOException{
//获取信息源
File f=new File("E:\\test.txt");
//创建IO流对象
FileInputStream f2=new FileInputStream(f);
//读取信息
int i=f2.read();
while(i!=-1){
System.out.print((char)i);
i=f2.read();
}
//关闭信息源
f2.close;
}
2,字节输出输入流读取输出图片:
public static void main(String[] args) throws IOException {
//获得数据源
File Inf=new File("E:小狮子.png");
File outf=new File("E:teat\\小狮子.png");
//获得输出流
FileInputStream f1=new FileInputStream(Inf);
FileOutputStream f2=new FileOutputStream(outf);//对应想要输出的地址
//读写信息
byte[] bys=new byte[50];//设置缓冲区,弥补read()一次只读一个字节的缺点
int i=f1.read(bys);
while (i!=-1){
f2.write(bys);//输出流对应write。
i=f1.read(bys);
}
//关闭资源;后开的先关
f2.close();
f1.close();
}
3字符流输入:(读取汉字)
public static void main(String[] args) throws IOException {
//获得数据源
File Inf=new File("E:test.txt");
//获取管道对象:
//读汉字
FileReader f=new FileReader(Inf);
char[] cs=new char[50];//缓冲区
int i=f.read(cs);
while (i!=-1){//下一位无内容时,条件不满足,停止循环
System.out.println(cs);
i=f.read(cs);//判断下一位是否有内容
}
//关闭
f.close();
}
4,字符流输出:
public static void main(String[] args) throws IOException {
//获得信息源
File file=new File("E:test.txt");
//获得字符输出流对象,输出管道
FileWriter fw=new FileWriter(file,true);//没有条件会覆盖当前test内容,有ture条件会在末尾追加。默认是false会覆盖内容。
//写入
Scanner input =new Scanner(System.in);
System.out.println("输入信息,输入exit退出");
String str=input.next();
while (!"exit".equals(str)){
fw.write(str+"\n");
System.out.println("输入信息,输入exit退出");
str=input.next();
}
//关闭流对象
fw.close();
}
4,缓冲字节流(处理流):
相较于使用缓冲区读取IO流信息,使用缓冲流更加快捷迅速。
public static void main(String[] args) throws IOException {
//1.有一个源图片
File f1 = new File("d:\\LOL.jpg");
//2.有一个目标图片:
File f2 = new File("d:\\LOL2.jpg");
//3.有一个输入的管道 接 到 源文件:
FileInputStream fis = new FileInputStream(f1);
//4.有一个输出的管道 接到 目标文件上:
FileOutputStream fos = new FileOutputStream(f2);
//5.功能加强,在FileInputStream外面套一个管:BufferedInputStream:
BufferedInputStream bis = new BufferedInputStream(fis);
//6.功能加强,在FileOutputStream外面套一个管:BufferedOutputStream:
BufferedOutputStream bos = new BufferedOutputStream(fos);
//7.开始动作 :
byte[] b = new byte[1024*6];
int len = bis.read(b);
while(len!=-1){
bos.write(b,0,len);
/* bos.flush(); 底层已经帮我们做了刷新缓冲区的操作,不用我们手动完成:底层调用flushBuffer()*/
len = bis.read(b);
}
//8.关闭流:
//倒着关:
//如果处理流包裹着节点流的话,那么其实只要关闭高级流(处理流),那么里面的字节流也会随之被关闭。
bos.close();
bis.close();
/*fos.close();
fis.close();*/
}
5,缓冲字符流(处理流):
public static void main(String[] args) throws IOException {
//1.有一个源文件:
File f1 = new File("d:\\Test.txt");
//2.有一个目标文件:
File f2 = new File("d:\\Demo.txt");
//3.需要一个管 接到 源文件:
FileReader fr = new FileReader(f1);
//4.需要一根管接到目标文件:
FileWriter fw = new FileWriter(f2);
//5.套一根管在输入字符流外面:
BufferedReader br = new BufferedReader(fr);
//6.套一根管在输出字符流外面:
BufferedWriter bw = new BufferedWriter(fw);
//7.开始动作:
//方式1:读取一个字符,输出一个字符:
/*int n = br.read();
while(n!=-1){
bw.write(n);
n = br.read();
}*/
//方式2:利用缓冲数组:
/*char[] ch = new char[30];
int len = br.read(ch);
while(len!=-1){
bw.write(ch,0,len);
len = br.read(ch);
}*/
//方式3:读取String:
String str = br.readLine();//每次读取文本文件中一行,返回字符串
while(str!=null){
bw.write(str);
//在文本文件中应该再写出一个换行:
bw.newLine();//新起一行
str = br.readLine();
}
//8.关闭流
bw.close();
br.close();
}
6,转换流(处理流):
【1】转换流:作用:将字节流和字符流进行转换。
【2】转换流 属于 字节流还是字符流?属于字符流
InputStreamReader :字节输入流 --->字符的输入流
OutputStreamWriter : 字符输出流 -->字节的输出流
//将输入的字节流转换为字符流
public static void main(String[] args) throws IOException {
//文件---》程序:
//1.有一个源文件:
File f = new File("d:\\Test.txt");
//2.需要一个输入的字节流接触文件:
FileInputStream fis = new FileInputStream(f);
//3.加入一个转换流,将字节流转换为字符流:(转换流属于一个处理流)
//将字节转换为字符的时候,需要指定一个编码,这个编码跟文件本身的编码格式统一
//如果编码格式不统一的话,那么在控制台上展示的效果就会出现乱码
//InputStreamReader isr = new InputStreamReader(fis,"utf-8");
//获取程序本身的编码--》utf-8
InputStreamReader isr = new InputStreamReader(fis);
//4.开始动作,将文件中内容显示在控制台:
char[] ch = new char[20];
int len = isr.read(ch);
while(len!=-1){
//将缓冲数组转为字符串在控制台上打印出来
System.out.print(new String(ch,0,len));
len = isr.read(ch);
}
//5.关闭流:
isr.close();
}
public static void main(String[] args) throws IOException {
//1.有一个源文件
File f1 = new File("d:\\Test.txt");
//2.有一个目标文件:
File f2 = new File("d:\\Demo.txt");
//3.输入方向:
FileInputStream fis = new FileInputStream(f1);
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
//4.输出方向:
FileOutputStream fos = new FileOutputStream(f2);
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//5.开始动作:
char[] ch = new char[20];
int len = isr.read(ch);
while(len!=-1){
osw.write(ch,0,len);
len = isr.read(ch);
}
//6.关闭流:
osw.close();
isr.close();
}
7,数据流(处理流):
【1】数据流:用来操作基本数据类型和字符串的
【2】 DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中
DataOutputStream: 将内存中的基本数据类型和字符串的变量 写出 文件中
//利用DataOutputStream向外写出变量:
public class Test01 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws IOException {
//DataOutputStream: 将内存中的基本数据类型和字符串的变量 写出 文件中
/*File f = new File("d:\\Demo2.txt");
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos = new DataOutputStream(fos);*/
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("d:\\Demo2.txt")));
//向外将变量写到文件中去:
dos.writeUTF("你好");
dos.writeBoolean(false);
dos.writeDouble(6.9);
dos.writeInt(82);
//关闭流:
dos.close();
}
}
//读取的程序:
public class Test02 {
//这是一个main方法,是程序的入口:
public static void main(String[] args) throws IOException {
//DataInputStream:将文件中存储的基本数据类型和字符串 写入 内存的变量中
DataInputStream dis = new DataInputStream(new FileInputStream(new File("d:\\Demo2.txt")));
//将文件中内容读取到程序中来:
System.out.println(dis.readUTF());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
//关闭流:
dis.close();
}
}
8,对象流(处理流);
【1】对象流:ObjectInputStream,ObjectOnputStream
用于存储和读取基本数据类型数据或对象的处理流。
它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
【2】序列化和反序列化:
ObjectOutputStream 类 : 把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据持久地保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点。---->序列化
ObjectInputStream类 : 当其它程序获取了这种二进制数据,就可以恢复成原来的Java对象。---->反序列化
//实验类
public class Student implements Comparable<Student>, Serializable {
/**
* 属性类型以包装类型存在!
*/
private Integer stuId;
private String stuName;
private Integer age;
private String sex;
public Student() {
}
public Student(Integer stuId, String stuName, Integer age, String sex) {
this.stuId = stuId;
this.stuName = stuName;
this.age = age;
this.sex = sex;
}
public Integer getStuId() {
return stuId;
}
public void setStuId(Integer stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) throws Exception {
this.age = age;
throw new Exception("提醒的内容");
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(stuId, student.stuId) &&
Objects.equals(stuName, student.stuName) &&
Objects.equals(age, student.age) &&
Objects.equals(sex, student.sex);
}
@Override
public int hashCode() {
return Objects.hash(stuId, stuName, age, sex);
}
@Override
public String toString() {
return "Student{" +
"stuId=" + stuId +
", stuName='" + stuName + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
@Override
public int compareTo(Student o) {
/*if(stuId>o.stuId){
return -1;
}else if(stuId<o.stuId){
return 1;
}else{
return 0;
}*/
return stuName.compareTo(o.stuName);
}
}
//序列化
public static void main(String[] args) throws IOException {
//使用对象流"将内存对象----存储到外部文件:序列化:永久存储信息
//将外部文件里信息,读取到内存:反序列化
//获得信息源对象:
File file=new File("E:test.txt");
//获得管道对象
//序列化,要有标记接口
FileOutputStream fos=new FileOutputStream(file);//节点流
ObjectOutputStream oos=new ObjectOutputStream(fos);//处理流
//开始序列化
Student stu=new Student(1,"xiao",24,"nan");
oos.writeObject(stu);
//关闭流对象,同一个方向,当有多层流对象时,关闭最里层。
oos.close();
System.out.println("序列化成功");
}
//反序列化
public static void main(String[] args) throws IOException, ClassNotFoundException {
//获得信息源对象:
File file=new File("E:test.txt");
//获得管道对象
//序列化,要有标记接口
FileInputStream fos=new FileInputStream(file);//节点流
ObjectInputStream oos=new ObjectInputStream(fos);//处理流
Student stu=(Student)oos.readObject();
System.out.println(stu);
oos.close();
System.out.println("反序列化成功");
}
补:
serialVersionUID:
凡是实现Serializable接口(标识接口)的类都有一个表示序列化版本标识符的静态常量:
➢private static final long serialVersionUID;
➢serialVersionUID用来表明类的不同版本间的兼容性。简言之,其目的是以序列化对象进行版本控制,有关各版本反序加化时是否兼容。
➢如果类没有显示定义这个静态变量,它的值是Java运行时环境根据类的内部细节自动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。故建议,显式声明。
➢简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常。(InvalidCastException)