0519课堂笔记--IO流-序列化与反序列化

本文深入讲解Java中的IO流概念及其实现方式,包括文件流、缓冲流等,并提供了文件复制的具体实现案例。此外,还详细介绍了序列化与反序列化的原理及应用。

1. IO流

1.1 流Stream

  1. 只能单方向流动
  2. 输入流in–输出流out–从程序角度
  3. 数据只能从头到尾的 顺序读写一次

1.2 IO流继承结构

1.2.1 File文件流

封装磁盘路径字符串,创建可操作对象

1.2.2 父类

​ 不可创建对象–学习父类提供的共性方法–通过子类创建可以操作的对象

​ InputStream–OutputStream–字节输入输出流 --针对二进制文件

​ Reader–Writer–字符输入输出流–针对文本文件

1.2.3 子类

​ FileInputeStream BufferedInputStream ObjectInputStream

​ FileOutputeStream BufferedOutputStream ObjectOutputStream

​ FileReader BufferedReader InputStreamReader

​ FileWriter BuffererdWriter OutputStreamWrite

FileInputeStream–直接插在文件上,直接读取文件数据

BufferedInputStream创建对象
BufferedInputStream(InputStream in)
创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

实例化:

InputStream in2 =new BufferedInputStream(new FileInputStream("D:\\ready\\1.txt"));

1.2.4 文件复制综合案例

package cn.tedu.file;
//测试文件复制案例
import java.io.*;
import java.util.Scanner;
/**
 * 需求:接受用户输入的文件路径来进行复制,复制到用户指定的路径下
 */
public class TestCopyFile {
    public static void main(String[] args) {
        //1.提示并接收两个路径
        System.out.println("请输入源文件路径");
        String f = new Scanner(System.in).nextLine();
        System.out.println("请输入目标文件路径");
        String t = new Scanner(System.in).nextLine();

        //2. 把接收到的路径进行封装变成可以进行文件操作的File对象
        File from = new File(f);
        File to = new File(t);

        //3. 调用复制方法进行复制
        ZJCopy(from, to);//自定义字节流复制文件的方法
        //ZFCopy(from, to);//自定义字符流复制文件的方法
    }

    public static void ZJCopy(File from, File to) {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new BufferedInputStream(new FileInputStream(from));
            out = new BufferedOutputStream(new FileOutputStream(to));
            int a = 0;
            while ((a = in.read()) != -1) {
                out.write(a);
            }
            System.out.println("文件复制完成");
        } catch (Exception e) {
            System.out.println("文件复制失败");
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void ZFCopy(File from, File to) {
        //注意局部变量需要初始化,null
        Reader in = null;//定义整个方法都生效的字符输入流抽象父类类型的变量
        Writer out = null;
        try {
            //通过输入流读取from--获取字符输入流对象
            in = new BufferedReader(new FileReader(from));
            //通过输出流输出to--获取字符输出流对象
            out = new BufferedWriter(new FileWriter(to));
            //定义变量--边读边写
            int a = 0;
            while ((a = in.read()) != -1) {
                out.write(a);//将本轮循环内容写出
            }
            System.out.println("文件复制完成");
        } catch (Exception e) {
            System.out.println("文件复制失败");
            e.printStackTrace();
        } finally {
            /**1. 流资源必须释放,释放的是之前使用过程中所以的流对象
             * 2. 关流是有顺序的,注意:后创建的先关流,为了不影响其他的代码,不能先关最先创建的流*/
            try {
                out.close();//关闭字符输出流
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                in.close();//关闭字符输入流
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

1.3 序列化与反序列化

1.3.1 概述

序列化:利用ObjectOutputStream,把对象信息按照固定格式转换成一串字节输出并持久保存到磁盘

反序列化:利用ObjectIntputStream,读取磁盘中之前序列化好的数据,从新恢复成对象

1.3.2 特点/应用场景

  1. 需要序列化的文件必须实现Serializable接口,用来启用序列化功能
  2. 不需要序列化的数据可以修饰成static,原因:static资源属于类资源,不随着对象被序列化输出
  3. 每一个被序列化的文件都有一个唯一的id,如果没有添加此id,编译器会自动根据类的定义信息计算产生一个
  4. 在反序列化时,如果和序列化的版本号不一致,无法完成反序列化
  5. 常用与服务器之间的数据传输,序列化成文件,反序列化读取数据
  6. 常用使用套接字流在主机之间传递对象
  7. 不需要序列化的数据也可以被修饰成transient(临时的),只在程序运行期间在内存中存在,不会被序列化持久保存

1.3.3 案例

创建封装学生类

package cn.tedu.seri;
import java.io.Serializable;
//封装学生类
/**本类如果想要实现序列化,必须实现可序列化接口,否则报错
 * 报错信息:NotSerializableException: cn.tedu.seri.Student
 * Serializable是一个空接口,里面一个方法都没有,
 * 作用:当作标志,标志着这个类可以被序列化*/
public class Student implements Serializable {
    /**需要给每个进行序列化的文件分配唯一的UID值*/
    //private static final long serialVersionUID  = 1l;//默认存在
    //1.定义并封装属性--提供get,set方法
    private int sno;//学号
    private String name;//姓名
    private String address;//住址
    private char gender;//性别
    //2.提供无参构造--必须手动提供午餐构造,否则会被含参构造覆盖
    public Student() {
        System.out.println("Student的无参构造");
    }
    //3.全参构造
    public Student(int sno, String name, String address, char gender) {
        this.sno = sno;
        this.name = name;
        this.address = address;
        this.gender = gender;
        System.out.println("Student的全参构造");
    }

    public int getSno() {
        return sno;
    }

    public void setSno(int sno) {
        this.sno = sno;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
    /**打印结果:cn.tedu.seri.Student@4dd8dc3
     * 查看属性值,重写toString*/
    @Override
    public String toString() {
        return "Student{" +
                "sno=" + sno +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", gender=" + gender +
                '}';
    }
}

测试序列化与反序列化

package cn.tedu.seri;
import java.io.*;
//测试序列化与反序列化
public class TestSerializable {
    public static void main(String[] args) {
        method();//测试序列化
        method2();//测试反序列化
    }
    /**序列化方法*/
    public static void method() {
        //声明在本方法中生效的系列化类型的变量,局部变量需要初始化--null
        ObjectOutputStream out = null;
        try {
            //1.创建用来序列化的流对象OOS
            out = new ObjectOutputStream(new FileOutputStream("D:\\ready\\1.txt"));
            //2.创建Student对象
            Student s = new Student(666,"泡泡","地球村",'男');
            //3.通过OOS流对象来序列化对象输出到指定文件
            out.writeObject(s);
            System.out.println("序列化成功");
        }catch (Exception e){
            System.out.println("序列化失败");
            e.printStackTrace();
        }finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**反序列化*/
    public static void method2() {
        ObjectInputStream in =null;
        try {
            in = new ObjectInputStream(new FileInputStream("D:\\ready\\1.txt"));
            Object o =in.readObject();
            System.out.println(o);
            System.out.println("反序列化成功");
        }catch (Exception e){
            System.out.println("反序列化失败");
            e.printStackTrace();
        }finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

注意:

  1. 序列化对象所在类要实现序列化接口

    public class Student implements Serializable {
    
  2. UID要保持一致或者序列化与反序列化同时操作,否则会报错

    手动添加UID,只要这个值不改变,就可以不论次数编译,进行序列化和反序列化操作

    private static final long serialVersionUID  = 1l;
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值