Java二进制文件读写Student对象遇StreamCorruptedException求助
解决Java对象流读取时的StreamCorruptedException问题
我开发了一款程序,支持输入学生信息写入二进制文件,后续可通过姓名查询信息。写入时用自定义MyObjectOutputStream跳过流头来追加对象,但读取时抛出StreamCorruptedException: invalid stream header: 73720007错误。
错误原因
- 对象流追加写入的结构问题:
ObjectOutputStream写入时会生成流头,自定义MyObjectOutputStream跳过了第一次的流头,但后续每次调用input()追加写入新对象时,虽然没有重复写流头,但读取时ObjectInputStream仍会尝试读取流头,而第二次及以后写入的对象数据前没有流头,导致解析失败。 - 流未正确关闭:
input()方法中没有关闭MyObjectOutputStream和FileOutputStream,导致资源泄漏,数据可能未完全刷入文件。 - 查询逻辑未实现:
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(); } } }
关键修改点
- 写入逻辑调整:每次先读取已有的学生列表,添加新学生后写入整个列表,避免追加对象流的结构问题。
- 流资源管理:使用
try-with-resources语法自动关闭ObjectInputStream和ObjectOutputStream,确保资源正确释放,数据完整写入。 - 查询逻辑实现:读取整个学生列表后,用
equals()方法匹配姓名,输出对应信息;处理文件为空的情况。 - 移除不必要的自定义流:不再需要
MyObjectOutputStream,因为现在每次写入整个列表,流头只写一次,读取时正常解析。
内容的提问来源于stack exchange,提问作者Magnus Bane
相关产品推荐
相关产品推荐

