序列化多个对象和反序列化遍历一个文件中的所有对象原理讲解

在这里插入图片描述
  若不进行处理,直接继续序列化添加对象进去。会在追加时继续写个头部的四个字节
在这里插入图片描述
直接读取时,报错!
在这里插入图片描述
在这里插入图片描述
下面和我们手动去掉;
在这里插入图片描述
再次运行!
成功读取
在这里插入图片描述

package com.gqzdev;

import com.gqzdev.bean.User;

import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: SeralizableTest
 * @author: ganquanzhong
 * @date: 2020/4/9 12:19
 */
public class SerializableTest implements Serializable {

    public static void main(String[] args) throws IOException {
        User user = new User(1001, "gqzdev-end"+new Date(), "女");
        File file = new File("E:/ser");

        /*
        //序列化对象
        serialize(user,file);
        //反序列化
        Object o =deserialize(file);
        System.out.println(((User)o).toString());
        */

        //序列化对象
        //serializeAppend(user,file);
        //反序列化
        List<User> objList = deserializeObjList(file);
        System.out.println(objList.size());
        for (User user1:objList) {
            System.out.println(user1.toString());
        }

    }

    /**
     * 序列化一个对象 , 并写到文件中
     */

    public static void  serialize(Object o,File file) throws IOException {
        ObjectOutputStream stream =new ObjectOutputStream(new FileOutputStream(file));
        try {
             stream.writeObject(o);
             stream.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 序列化多个对象!!!
     * 使用ObjectOutputStream会调用writeStreamHeader();
     * 自动带上一个头aced 0005(占4个字节),然后每次读取都读完头然后在读内容。
     * 导致追加数据时发生错误。解决方法就是先判断文件是否存在。如果不存在,就先创建文件。追加的情况就是当判断文件存在时,把那个4个字节的头aced 0005截取掉,然后在把对象写入到文件。这样就实现了对象序列化的追加

     *
     *
     * 但是呢在读取的时候只有读取一次StreamHeader的,所以导致出错
     *
     * 解决方法,在序列化对象时,只保证写一次  StreamHeader
     */
    public static void  serializeAppend(Object obj,File file) throws IOException {
        //如果文件存在  就追加到后面  append
        boolean isexist=false;
        if (file.exists()){
            isexist=true;
        }

        FileOutputStream fileOutputStream=new FileOutputStream(file,true);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

        // 每次new的时候都会写入一个StreamHeader,所以要把屁股后面的StreamHeader去掉
        // 主要是处理fileOutputStream流的指针位置
        // 可以说是文件的长度
        long pos = 0;
        if (isexist) {
            // getChannel()返回此通道的文件位置,这是一个非负整数,它计算从文件的开始到当前位置之间的字节数
            pos = fileOutputStream.getChannel().position() - 4;// StreamHeader有4个字节所以减去
            // 将此通道的文件截取为给定大小
            fileOutputStream.getChannel().truncate(pos);
            System.out.println("追加成功~");
        }

        objectOutputStream.writeObject(obj);
        // 关闭流
        objectOutputStream.close();
    }


    /**
     *  从文件中,反序列化读取到object中
     */

    public static Object  deserialize(File file) throws IOException{
        ObjectInputStream stream = new ObjectInputStream(new FileInputStream(file));
        try {
            Object o = stream.readObject();
            stream.close();
            return o;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<User> deserializeObjList(File file) throws IOException{
        List<User> list = new ArrayList<>();
        FileInputStream fileInputStream = new FileInputStream(file);
        ObjectInputStream stream = new ObjectInputStream(fileInputStream);
        try {
            //遍历所有对象 available() > 0代表流中还有对象
            while (fileInputStream.available()>0){
                Object o = stream.readObject();
                System.out.println(((User)o).toString());
                list.add((User)o);
            }
            System.out.println("read-->"+list.size());
            stream.close();
            return list;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }



}

posted @ 2020-04-10 12:32  gqzdev  阅读(555)  评论(0编辑  收藏  举报