You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java二进制文件读写Student对象遇StreamCorruptedException求助

解决Java对象流读取时的StreamCorruptedException问题

我开发了一款程序,支持输入学生信息写入二进制文件,后续可通过姓名查询信息。写入时用自定义MyObjectOutputStream跳过流头来追加对象,但读取时抛出StreamCorruptedException: invalid stream header: 73720007错误。

错误原因

  1. 对象流追加写入的结构问题:ObjectOutputStream写入时会生成流头,自定义MyObjectOutputStream跳过了第一次的流头,但后续每次调用input()追加写入新对象时,虽然没有重复写流头,但读取时ObjectInputStream仍会尝试读取流头,而第二次及以后写入的对象数据前没有流头,导致解析失败。
  2. 流未正确关闭:input()方法中没有关闭MyObjectOutputStream和FileOutputStream,导致资源泄漏,数据可能未完全刷入文件。
  3. 查询逻辑未实现:setname()方法中创建了ArrayList但未填充数据,无法完成姓名匹配;且字符串比较用==,应该用equals()方法。

解决方案

推荐将所有学生对象存入ArrayList,每次写入整个列表到文件,这样读取时直接读取整个列表,避免追加对象流的结构问题。同时使用try-with-resources自动管理流资源,确保流正确关闭。

修正后的完整代码

import java.util.*;
import java.io.*;

interface IIITN {
    final String InstituteName = "IIIT Nagpur";
}

class Student implements Serializable {
    String name;
    String RollNo;
    String branch;
    String gender;
    String Degree;

    Student(String name, String RollNo, String branch, String gender, String Degree) {
        this.name = name;
        this.RollNo = RollNo;
        this.branch = branch;
        this.gender = gender;
        this.Degree = Degree;
    }
}

class CSE implements IIITN {
    public void input(File studentFile) throws IOException, ClassNotFoundException {
        Scanner sc = new Scanner(System.in);
        System.out.print("输入姓名: ");
        String name = sc.next();
        System.out.print("输入学号: ");
        String RollNo = sc.next();
        System.out.print("输入专业: ");
        String branch = sc.next();
        System.out.print("输入性别: ");
        String gender = sc.next();
        System.out.print("输入学位: ");
        String Degree = sc.next();

        // 读取已有的学生列表
        ArrayList<Student> studentList = new ArrayList<>();
        if (studentFile.exists() && studentFile.length() > 0) {
            try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(studentFile))) {
                studentList = (ArrayList<Student>) ois.readObject();
            }
        }

        // 添加新学生
        studentList.add(new Student(name, RollNo, branch, gender, Degree));

        // 写入整个列表到文件
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(studentFile))) {
            oos.writeObject(studentList);
        }
    }

    public void queryByName(File studentFile) throws IOException, ClassNotFoundException {
        Scanner sc = new Scanner(System.in);
        System.out.println("输入要查询的学生姓名: ");
        String targetName = sc.next();

        if (!studentFile.exists() || studentFile.length() == 0) {
            System.out.println("文件中无学生数据");
            return;
        }

        // 读取整个学生列表
        ArrayList<Student> studentList;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(studentFile))) {
            studentList = (ArrayList<Student>) ois.readObject();
        }

        // 匹配姓名查询
        boolean found = false;
        for (Student student : studentList) {
            if (student.name.equals(targetName)) {
                System.out.println("找到学生信息:");
                System.out.println("姓名: " + student.name);
                System.out.println("学号: " + student.RollNo);
                System.out.println("专业: " + student.branch);
                System.out.println("性别: " + student.gender);
                System.out.println("学位: " + student.Degree);
                found = true;
                break; // 找到第一个匹配的就退出,如需多个匹配可去掉break
            }
        }

        if (!found) {
            System.out.println("未找到姓名为" + targetName + "的学生");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        CSE c1 = new CSE();
        File f = new File("./CSE.txt");
        try {
            // 输入两个学生信息
            c1.input(f);
            c1.input(f);
            // 查询学生
            c1.queryByName(f);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

关键修改点

  1. 写入逻辑调整:每次先读取已有的学生列表,添加新学生后写入整个列表,避免追加对象流的结构问题。
  2. 流资源管理:使用try-with-resources语法自动关闭ObjectInputStream和ObjectOutputStream,确保资源正确释放,数据完整写入。
  3. 查询逻辑实现:读取整个学生列表后,用equals()方法匹配姓名,输出对应信息;处理文件为空的情况。
  4. 移除不必要的自定义流:不再需要MyObjectOutputStream,因为现在每次写入整个列表,流头只写一次,读取时正常解析。

内容的提问来源于stack exchange,提问作者Magnus Bane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 13:45:37