二刷能变强系列-IO流

一.IO流概述

在Java程序中,对于数据的输入/输出操作以"流" (stream)方式进行;Java提供了各种各样的“流"类,用以获取不同种类的数据;程序中通过标准的方法输入或输出数据。Java的流类型一般位于java.io包中。

二.流的分类

输出流输入流

我们想想平时我们在windows移动文件的时候是要进行什么操作,是不是先找到原文件然后复制,在去到目的地粘贴原文件。这里的原文件就是数据源,去到目的地粘贴原文件就是目的地,中转站在windows是内部帮我做的处理,在开发中我们的中转站可以看成是一个程序。
在这里插入图片描述

输出流:数据流向是数据源到程序(一般以InputStream,Read结尾)
输出流:数据流向是程序到目的地(一般以OutputStream,Write结尾)

输入输出流是相对于程序而言的,程序读取源文件,是不是数据往中转站里写,就是输入流。程序写数据到目的,是不是数据从程序里出去,就是输出流。

字节流字符流

字节流:以字节为单位获取数据的流(一般以InputStream,OutputStream结尾),可以传输任何文件(音频,文本等)。
字符流:以字符为单位获取数据的流(一般以Read,Write结尾),只能获取用记事本能打开的文件。

其实在java中只有字节流,字符流的底层使用的其实也是字节流。

节点流处理流

节点流:直接从数据源或目的地读写数据(FileInputStream,FileRead)。
处理流:不直接从数据源或目的地读写数据(BufferInputStream,BufferRead)。
在这里插入图片描述
节点流和处理流关系
只有节点流可以和数据直接连接,处理流不能,但是处理流能对节点流进行包装,提高性能和灵活性

数据流对象流

数据流:可以方便的对基本数据类型和引用数据类型(String)进行数据读写,并保留其本身的数据类型。如 DataInputStream(字节流,处理流)
对象流:可以方便的对引用数据类型进行数据读写,并保留其本身的数据类型。如 ObjectInputStream(字节流,处理流)

序列化与反序列化
在使用对象流的时候,我们需要对对象实现Serializable接口。因为我们的对象是存储在jvm中的方法区和堆中的,当我们需要将对象存在外部内存中,外部内存是没有jvm的这些区域,所以需要实现Serializable接口将对象转化为二进制数据保存。

import java.io.*;

public class ioLearn1 {
    public static void main(String[] args) throws Exception {
        write();
        read();
    }

    //读文件
    public static void read() throws Exception {
        InputStream is = new FileInputStream("D:\\IoLearn\\readme.txt");
        BufferedInputStream bis = new BufferedInputStream(is);
        ObjectInputStream ois = new ObjectInputStream(bis);
        System.out.println(ois.readInt());
        System.out.println(ois.readUTF());
        System.out.println(ois.readBoolean());
        Student s = (Student)ois.readObject();
        System.out.println(s.getName());

        //关闭流
        ois.close();
    }

    //写文件
    public static void write() throws Exception{
        //节点流 字节流
        OutputStream os = new FileOutputStream("d:/IoLearn/readme.txt");
        //缓冲流
        BufferedOutputStream bos = new BufferedOutputStream(os);
        //处理流 字节流
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeInt(1);
        oos.writeUTF("bug一定有");
        oos.writeBoolean(true);
        Student s = new Student("王二愣",20);
        oos.writeObject(s);

        //关闭流
        oos.close();
    }
}

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID=7981560250804078637l;
    String name ;
    int age ;

    public Student() {

    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

这里有个问题???
Q:为什么Serializable接口里没东西还要实现它进行序列化
A:我们点ObjectOutputStream里的writeObject->writeFatalException开源码看看就知道怎么回事了,在源码中,我们会判断该对象是否是Serializable会对对象进行特殊处理。

// remaining cases
   if (obj instanceof String) {
       writeString((String) obj, unshared);
   } else if (cl.isArray()) {
       writeArray(obj, desc, unshared);
   } else if (obj instanceof Enum) {
       writeEnum((Enum<?>) obj, desc, unshared);
   } else if (obj instanceof Serializable) {
       writeOrdinaryObject(obj, desc, unshared);
   } else {
       if (extendedDebugInfo) {
           throw new NotSerializableException(
               cl.getName() + "\n" + debugInfoStack.toString());
       } else {
           throw new NotSerializableException(cl.getName());
       }
   }

三.流的体系结构

在这里插入图片描述

四.IO流使用报错异常

NotSerializableException

Exception in thread "main" java.io.NotSerializableException: com.wq.ioLearn.Student

(1)对应的类没有实现Serializable接口。

(2)类对象里还包含类对象,包含的类对象需要要实现Serializable接口

InvalidClassException

Exception in thread "main" java.io.InvalidClassException: com.wq.ioLearn.Student; local class incompatible: stream classdesc serialVersionUID = 2327102107518923782, local class serialVersionUID = 3821233561147490119

序列化会有一个版本号控制,当对应的对象进行修改后,序列化的版本号也会有对应的修改,写读的版本号不一值的时候会出现这样的异常。

可以在对应的实体类里定义

 private static final long serialVersionUID=7981560250804078637l; 

EOFException

Exception in thread "main" java.io.EOFException

ObjectOutputStream和ObjectInputStream(DataOutputStream和DataInputStream)数据要按顺序读取,比如先writeInt->writeUTF->writeBoolean就要readInt->readUTF->readBoolean,少读没问题,多读会报错。

五.结束语

以前刚学IO流的时候,劈里啪啦,劈里啪啦一大堆类直接砸过来,懵逼的我怎么可能记得住这么多,后来也就不了了之了,再回过头来看看,数据的分类和规则其实理解了也没那么难记,果然二刷能变强。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值