0

I am writing a small program that inserts customer details in ArrayList and write it in file.

The problem is with ObjectOutputStream I was able to append data in file with turning FileOutputStream("",true). But when I try to read data with ObjectInputStream it only reads data that was inserted at first instance. But data is being added to file.

Here is the code -

public void insertCustomer() throws IOException 
{       
        Customer1=new customerDetails("1", "Moeen4", "654654", "asdf", "coding", "student", "65464", "3210");
        Customer3=new customerDetails("3", "Moeen5", "888888", "asdf", "coding", "student2", "65464", "321022");
        Customer4=new customerDetails("4", "Moeen6", "654654", "asdf", "coding", "student", "65464", "7890");
        
        _list=new ArrayList<customerDetails>();
        _list.add(Customer1);
        _list.add(Customer3);
        _list.add(Customer4);
        
        customersList cl=new customersList();
        
        cl.WriteObjectToFile(files._customers, _list);
        
        ArrayList<customerDetails>li=new ArrayList<customerDetails>();
        li= (ArrayList) cl.ReadObjectFromFile(files._customers);           
        for(int i=0;i<li.size();i++)
        {   System.out.println(li.size());
            System.out.println(li.get(i).Id);
            System.out.println(li.get(i).name);
            System.out.println(li.get(i).annual_Salary);
            System.out.println(li.get(i).Company);
            System.out.println(li.get(i).dateOfBirth);
            System.out.println(li.get(i).phone_Number);
        }
    }


public void WriteObjectToFile(String filepath,Object serObj) {       
    try {
        
        FileOutputStream fileOut = new FileOutputStream(filepath,true);
        ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
        objectOut.writeObject(serObj);
        objectOut.close();
        System.out.println("The Object  was succesfully written to a file");

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

public Object ReadObjectFromFile(String filepath) {      
    try {

        FileInputStream fileIn = new FileInputStream(filepath);
        ObjectInputStream objectIn = new ObjectInputStream(fileIn);

        Object obj = objectIn.readObject();
        objectIn.close();
        System.out.println("The Object has been read from the file");
        
        return obj;

    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}
clD
  • 2,031
  • 1
  • 18
  • 32
MoinAhmad
  • 9
  • 3
  • 3
    You are only reading one ArrayList from the file. When you write a second time another ArrayList is appended to the end of the file. You will need to keep reading ArrayLists until you reach the end of the file. – tgdavies Dec 22 '20 at 08:32
  • any function to read till the end of the file? – MoinAhmad Dec 22 '20 at 16:48
  • You can't do this. You can't append to an `ObjectOutputStream` without taking special measures. It would be best to either keep the file open or completely rewrite it each time. – user207421 Dec 23 '20 at 00:36
  • See [`StreamCoccruptedException: invalid type code AC`](https://stackoverflow.com/questions/2393179/streamcorruptedexception-invalid-type-code-ac). – user207421 Dec 23 '20 at 00:50

2 Answers2

1

The real problem here is this:

  FileOutputStream fileOut = new FileOutputStream(filepath, true);
  ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
  objectOut.writeObject(serObj);

You cannot append to an existing serialization like this. If you do get an exception when attempting to read any objects appended to a pre-existing (non-empty) file.

There is a trick / hack that allows you to append objects though; see Appending to an ObjectOutputStream. (The trick involves suppressing the writing of the object stream header. It is most easily done by overriding the method that does this.)

The other approach is to keep the ObjectOutputStream open between writeObject calls. However there are use-cases where that won't be possible.

Note that there is a semantic difference between these two approaches. The best way to explain it is that the first one behaves as if you called reset() each time you write an object; see the javadoc.


Another thing to note about your example is that your reader code only reads one object. If you want to read multiple objects, you need to call readObject in a loop. And that will only work if you have used the trick / hack above to avoid writing a spurious header.

Stephen C
  • 632,615
  • 86
  • 730
  • 1,096
-2

As suggested the code is only reading the first object and you would need to use a loop to read all the objects from multiple writes.

However -

If you change the above code i.e. ReadObjectFromFile to use a loop this will lead to an StreamCorruptedException: invalid type code: AC. The ObjectOutputStream constructor writes a serialization stream header to the OutputStream i.e. the file, when it is closed and reopend using new ObjectOutputStream and new FileOutputStream(filepath, true) a new header will be written at the append point so you will get an exception as the header is only expected once at the beginning of the file

This will need to be handled e.g.

  • Use the same ObjectOutputStream for the duration
  • Override java.io.ObjectOutputStream.writeStreamHeader() to account for append to a file
  • Change the approach and use List<List<Object>> which you could read, add, write to as a whole.

Loop example would throw exception unless ObjectOutputStream approach is changed

public Object ReadObjectFromFile(String filepath) {
    
    List<List<Object>> objects = new ArrayList<>();
    
    FileInputStream fileIn = new FileInputStream(filepath);
    ObjectInputStream objectIn = new ObjectInputStream(fileIn);
    
    try {
        while (true) {
            List<Object> obj = (List<Object>) objectIn.readObject();
            // This will throw StreamCorruptedException: invalid type code: AC
            objects.add(obj);
            System.out.println("The Object has been read from the file");                
        }
    } catch (EOFException ex) {
        // ENDS WHEN ALL READ
    } finally {
        fileIn.close();
        objectIn.close();
    }
    
    return objects;
}

Sudo code List<List<Object>> approach -

public void readAndWrite() {
    List<Object> customer = List.of(new CustomerDetails(...),
                                    new CustomerDetails(...),
                                    new CustomerDetails(...));
    
    List<List<Object>> objects = readFromFile("existing-customer-file.txt");

    objects.addAll(customer);
    
    writeObjectToFile(objects);
}
clD
  • 2,031
  • 1
  • 18
  • 32
  • `ObjectnputStream doesn't read lines at all, it reads objects, but you can certainly read as many as you like, as your ownn code demonstrates. However in the OP's context this code will fail for another reason. – user207421 Dec 23 '20 at 00:35
  • @user207421 The OP did not mention exceptions was being caught and yes it would also fail with AC error, you are right the use of the word lines would have been better as `header` I have update this, the comment was suppose to suggest a `List` would be cleaner – clD Dec 23 '20 at 08:37
  • The use of the word 'objects' would have been better than either 'lines' or 'header', wherever you got that from. The OP didn't mention exceptions because he didn't get an exception, but he will, as you agree. And 'using `catch` block to control programme flow' is *not* 'considered as bad practice by most'. That is exactly what it is for. And the OP doesn't cease using append mode when opening the file, which you haven't mentioned, he will continue to get the `invalid type code: AC` from the code you have posted. – user207421 Dec 23 '20 at 08:43
  • "OP didn't mention exceptions because he didn't get an exception, but he will, as you agree" - this is why it was not in the original answer. Generally reading a file knowing it will throw `Exception` is widely considered an anti pattern instead of say something like `while(!(obj = inputStream.readObject()).equals(null))` and avoiding it. – clD Dec 23 '20 at 08:52