javaIO流(2)

一.字符流

字符流对数据的操作是以一个个字符为单位的,字符流只能读文本文件,并将读到的字节按照编码表转为对应的字符,Reader和Writer是字符流的两个最大的抽象类,InputStreamReader和OutputStreamWriter分别继承了Reader和Writer,它俩的功能就是将读取到的字节转换为字符,所以又被称为转换流

1. FileReader和FileWriter读写文件

FileReader常用方法方法阐述
FileReader(String fileName)构造方法,用来指定要读的文件
int read()读取一个字符,返回读到的字符的码值,如果读到-1则表示读取完毕
int read(char[] chars)一次读一个字符数组,返回实际读取到的字符个数

FileWriter常用方法方法阐述
FileWriter(String fileName,boolean append)构造方法,用来指定要写入的文件,并且可以设置是追加,还是覆盖当前内容
void writer(int c)一次写一个字符
void writer(char[] chars,in off,int len)一次写一个字符数组,从字符数组的off位置开始,写len个

1.1  一个字符一个字符读

public class CharDemo1 {
    public static void main(String[] args) throws IOException {

        /*
        字符流只能读文本文件,会将读到字节结合编码表转换为一个字符编码
         */

        //一次读一个字符

        FileReader fileReader = new FileReader("E:/demo.txt");
        FileWriter fileWriter = new FileWriter("E:/demo1.txt");
        int c = 0;
        while((c = fileReader.read())!=-1){
            fileWriter.write(c);
        }
        fileReader.close();
        fileWriter.close();
    }
}

1.2  一次读一个字符数组

public class CharDemo2 {
    public static void main(String[] args) throws IOException {


        /*
        字符流只能读文本文件,会将读到字节结合编码表转换为一个字符编码
         */


        //一次读一个char数组
        FileReader fileReader = new FileReader("E:/demo.txt");
        FileWriter fileWriter = new FileWriter("E:/demo1.txt");
        int size = 0;
        char[] chars = new char[10];
        while((size = fileReader.read(chars))!=-1){
            fileWriter.write(chars,0,size);
        }
        fileReader.close();
        fileWriter.close();
    }
}

2. 字符缓冲流(包装流)

BufferedReader常用方法方法阐述
BufferedReader(Reader in)构造方法,可以传入一个Reader类对象
String readLine()一次读一行数据

BufferedWrite常用方法方法阐述
BufferedWriter(Writer our)构造方法,可以传一个Writer类对象
void write(String s)一次写一个字符串
void newLine()写一个换行符

2.1 BufferedReader和BufferedWriter读写文件

BufferReader和BufferWriter是两个包装流,可以对节点流FileReader和FileWriter进行包装,支持一次读写一行数据大大提高了数据的读写效率,FileWriter的构造方法中可以增加一个布尔类型的参数,表示写入文件的内容不会覆盖原内容,而是追加到文件原有内容的后面,bufferWriter中的newLine()方法表示写入一个换行符到文件中

public class CharDemo3 {
    /*
    字符流只能读文本文件,会将读到字节结合编码表转为一个字符编码
     */

    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("E:/demo.txt");
        FileWriter fileWriter = new FileWriter("E:/demo1.txt",true);//保留原来的内容,在原内容基础上向后追加(续写)
        BufferedReader bufferedReader = new BufferedReader(fileReader);
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
        String s = null;
        while((s=bufferedReader.readLine())!=null){
            bufferedWriter.write(s);
            bufferedWriter.newLine();//插入换行符
        }
        bufferedReader.close();
        bufferedWriter.close();
    }
}

2.2  BufferReader从控制台读取数据

public class CharDemo4 {
    public static void main(String[] args) throws IOException {
        /*
          利用BufferReader从控制台读取内容
     */

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入字符串");
        String s = bufferedReader.readLine();
        System.out.println(s);
    }

}

二.  对象输入输出字节流

对象输入流(ObjectInputStream):从文件中把对象输入到程序中

对象输出流(ObjectOutputStream):把java中的对象输出到文件中

这两个属于包装流,可以对字节输入流和字节输出流进行包装处理

1. 为什么要把对象输入到文件中

这是因为我们在程序中new的对象都存在内存中,当程序运行结束后,对象会随着销毁,无法做到将对象的信息永久保存,但有时我们有这种将对象信息永久保存的需求,在需要的时候在还原到程序中.

例如:平时一个游戏凌晨更新维护的时候,往往需要关闭服务器,那我们玩家的账号信息肯定要保存下来,等到维护完成,再将数据恢复到相应的玩家账号中

2. 对象的序列化和反序列化

对象的序列化:将对象信息从程序写到文件中保存

对象的反序列化:将对象信息从文件读到程序中

对象的序列化通过对象输出流来实现(ObjectOutputStream)

ObjectOutputStream常用方法方法阐述
ObjectOutputStream(OutputStream out)构造方法,传入一个字节输出流对象
writeObject(Object obj)将一个对象信息写入文件中

对象的反序列化通过对象输入流来实现(ObjectInputStream)

ObjectInputStream常用方法方法阐述
ObjectInputStream(InputStream in)构造方法,传入一个字节输入流对象
Object readObject(Object obj)从文件中读一个对象信息,并返回该对象

由Object readObject(Object obj)看出,字节输入流也是创建对象的一种方式

import java.io.Serializable;

/*
如果一个类需要被序列化到文件中,那么这个类就需要实现Serializable接口,实现后,会自动的为该类生成一个序列化编号
编号是类的唯一标识

但是自动生成的编号在类信息改变后,会重新为类生成一个编号

可以在类中显示的生成一个编号,这样类信息修改后,也不会改变
 */

public class Student implements Serializable {

    private static final long serialVersionUID = 771652260758459933L; //类的序列化编号
    private int num;

    private String name;

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

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

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public static void main(String[] args) throws IOException, ClassNotFoundException {

        //当一个类的对象需要被序列化到文件时,这个类必须要生成一个序列化编号
        Student student = new Student(100,"jim");

        //对象序列化
        FileOutputStream fileOutputStream = new FileOutputStream("E:/demo.txt");
        ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
        outputStream.writeObject(student);
        outputStream.close();

        //对象的反序列化
        FileInputStream fileInputStream = new FileInputStream("E:/demo.txt");
        ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
        Student stu = (Student)inputStream.readObject();
        System.out.println(stu);
        inputStream.close();
    }
}

 

自定义一个学生类,要想通过对象输入输出流对自定义的类进行序列化和反序列化,就必须实现Serializable接口,实现这个接口的类默认会生成一个序列化编号,这个编号就相当于一个身份证号一样,若类发生改变会重新生成一个序列化编号,当我们从文件中读取对象信息时,就是通过这个序列化编号去寻找是哪一个类的对象.

正因为类发生变化,序列化编号也会跟着变化,那么如果我们需要修改类信息时,下一次就无法完成反序列化, 因为编译器会拿着这次修改的编号去文件中找,但是文件中还存储的是上一次序列化时产生的编号,显然两次编号不同,编译器会认为这不是同一个类,即不是我们要反序列化的类,就会报错

解决方法:

显示生成序列化编号,这样对于这个类来说,无论怎么修改,它的序列化编号都不发生改变,但切记修改类信息后需要重新序列化对象,否则反序列化的扔是上次未修改的对象

3. IDEA设置序列化编号提示

 

注意这是新版IDEA的操作,设置好后点击OK即可,这样在自定义的类中如果实现了Serializable接口,鼠标放到类名上就会显示

 

此时编译器就会自动生成一个序列化编号,这样无论怎么修改类信息,在对象进行序列化和反序列化时都不会报错,唯一需要注意的是,如果修改了类的信息,需要自己重新将对象序列化一次,才是修改后的对象信息,否则还是保存的上一次未修改的对象的信息

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值