0

I am working on a school project that basically allows the user to create, edit and display students. I have a createStudent() that writes the info into the file using Scanner and ObjectOutputStream. The displayStudent() reads the data from the file using ObjectInputStream and displays it. The idea with editStudent() is to ask the user to enter the ID of the student they want to edit and then change the date and write it back to the file, what I have been trying to do is read the data from the file using ObjectInputStream and then assign that data into ArrayList or HashMap, I think I will be using ArrayList because HashMap is unordered. When I try to add the data from the file into ArrayList I get the following error:

java.io.EOFException at java.base/java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:3231) at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1663) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:519) at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:477) at MidTermProject.editStudent(MidTermProject.java:194) at MidTermProject.main(MidTermProject.java:381) Here is my code for editStudent():

public static void editStudent() throws IOException {
        
        int editID;
        String student;
        ArrayList<String> studentEdit = new ArrayList<String>();
        
        Scanner keyboard = new Scanner(System.in);
        
        FileInputStream fstream = new FileInputStream("studentInfo.dat");
        ObjectInputStream inputFile = new ObjectInputStream(fstream);
        
        System.out.print("Enter the ID of the student you would like to edit: ");
        editID = keyboard.nextInt();
        
        try {
            student = (String) inputFile.readObject();
            studentEdit.add(student);
            System.out.print(studentEdit);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
///Added create student method
public static void createStudent() throws IOException {
        
        File file = new File("studentInfo.dat");
        boolean append = file.exists();
        
        Scanner keyboard = new Scanner(System.in);
            
        try (
                FileOutputStream fout = new FileOutputStream(file, append);
                MidTermProject oout = new MidTermProject(fout, append);
            ) {
            id = idGenerator.getAndIncrement();
            String convertedId = Integer.toString(getId());
            oout.writeObject(convertedId);
                
            System.out.print("\nPlease enter your information bellow.\n" + "\nFull Name: ");
            FullName = keyboard.nextLine();
            oout.writeObject(FullName);
                
            System.out.print("Address: ");
            address = keyboard.nextLine();
            oout.writeObject(address);
                
            System.out.print("City: ");
            city = keyboard.nextLine();
            oout.writeObject(city);
                
            System.out.print("State: ");
            state = keyboard.nextLine();
            oout.writeObject(state);
            
            oout.close();
            System.out.println("Done!\n");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }

Here is the class code for MidTermProject

public class MidTermProject  extends ObjectOutputStream {

    private boolean append;
    private boolean initialized;
    private DataOutputStream dout;
    static AtomicInteger idGenerator = new AtomicInteger(0001);
    static int id;
    public static String FullName;
    public static String address;
    public static String city;
    public static String state;
    public static String className;
    public static String instructor;
    public static String department;
    public static String classNumber;
    public static String courseNumber;
    public static String year;
    public static String semester;
    public static String grade;
    public static String studentID;
    public static String courseID;
    public static String enrollmentID;
    
    public static HashMap<String, Integer> map = new HashMap<>();
    
    Scanner keyboard = new Scanner(System.in);
    
    protected MidTermProject(boolean append) throws IOException, SecurityException {
        super();
        this.append = append;
        this.initialized = true;
    }
    
    public MidTermProject(OutputStream out, boolean append) throws IOException {
        super(out);
        this.append = append;
        this.initialized = true;
        this.dout = new DataOutputStream(out);
        this.writeStreamHeader();
    }
    
    @Override
    protected void writeStreamHeader() throws IOException {
        if (!this.initialized || this.append) return;
        if (dout != null) {
            dout.writeShort(STREAM_MAGIC);
            dout.writeShort(STREAM_VERSION);
        }
    }
  • How do you write the file? – NoDataFound May 21 '21 at 18:10
  • How does data look in the file? Does it have any common format? – deHaar May 21 '21 at 18:13
  • I would strongly advise against using ObjectInput/OutputStream (as well as the Data Streams). Instead, I'd recommend using XML or JSON. It will be more stable in the long term if you need to change your student classes, as well as accessible in other technologies – ControlAltDel May 21 '21 at 18:15
  • I have a strange feeling that `ObjectInputStream` is wrongly used here. Are you sure you know what it does? https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html – Tarmo May 21 '21 at 18:22
  • I just added in the code the create student method so you can see how it writes the data into the file. Hope it makes more sense – RogerSampritas May 21 '21 at 18:26
  • @NoDataFound here is an example of how it writes the data `System.out.print("Address: "); address = keyboard.nextLine(); oout.writeObject(address);` – RogerSampritas May 21 '21 at 18:28
  • @ControlAltDel I would definitely be open to those options. but at school we are using the starting out with java book and have to use what is used in the book. – RogerSampritas May 21 '21 at 18:30
  • Can you post the MidTermProject constructor (and I'm assuming it extends ObjectOutputStream)? – eattrig May 21 '21 at 18:35
  • @eattrig just added it – RogerSampritas May 21 '21 at 18:42
  • The line `this.dout = new DataOutputStream(out);` causes problems because you have two stream handles writing to the same file. Try just calling `super.writeStreamHeader()` and getting rid of `dout`. – eattrig May 21 '21 at 18:53
  • @RogerSampritas You should definitely let "them" know that learning how to use these streams will not help you (and may hurt you if you rely on them) in any programming you do subsequently – ControlAltDel May 21 '21 at 18:59
  • Seems like you should be creating a Student object/class and writing that. (So don't write line by line...) It'll make things easier... it's the whole point of using ObjectWriter/Reader methods. You'll want to be careful about the structure of the file/classes. The class used needs to be serializable. (This way of storing data is avoided because it's difficult to provide forwards compatibility... but can be faster than a XML or JSON format) – pcalkins May 21 '21 at 19:13
  • So build an ArrayList()... iterate through to write or read. That'll keep the structure you need when using the stream... also be sure to close streams when done with them. (You might even use a single class with the array as a property...) – pcalkins May 21 '21 at 19:22
  • You write a header in your constructor. Do you read the header when you read the file data? – NomadMaker May 21 '21 at 20:00

1 Answers1

1

If think you are misusing serialization: whether Serialization is bad or good is another matter, but that should be something like that:

List<Student> students = ... ; 
try (OuputStream os = Files.newOutputStream(Paths.get("out"));
     ObjectOutputStream oos = new ObjectOutputStream(os)) {
  oos.writeObject(students);
}

Reading it should be as simple as:

try (InputStream is = Files.newInputStream(Paths.get("out"));
     ObjectInputStream iis = new ObjectInputStream(is)) {
  List<Student> students = iis.readObject(students);
}

You must ensure that Student is Serializable and have only Serializable or transient fields:

class Student implements Serializable {
  private static final long serialVersionUID  = 1L;
  private long id;
  private String fullName;
  private String address;
  private transient String wontBeExported;
  ...
}

Notice that the fields are not static: serialization is about serializing an object and its fields. Static fields are not part of any instance.

You should also not have to extends the ObjectOutputStream class, or if you do, you must ensure that you read the object written by your implementation of ObjectOutputStream is symmetric with the ObjectInputStream you are using:

  • If you write an header, your ObjectInputStream must read said header.
  • If you write an object, your ObjectInputStream must read said object.

And the order is important: you can't read the object before the header is read.

You should also read the Java tutorial: https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html

NoDataFound
  • 11,381
  • 33
  • 59