Objectoutputstream only saves the first object

Asked

Viewed 927 times

5

I’m trying to manipulate a Byte file with Java. In the writing of the file I have the following code:

FileOutputStream fos = new FileOutputStream("files\\Produtos.dat",true);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(P);
oos.close();

fos = new FileOutputStream("files\\Produtos.dat",true);
oos = new ObjectOutputStream(fos);
oos.writeObject(P2);
oos.close();

fos = new FileOutputStream("files\\Produtos.dat",true);
oos = new ObjectOutputStream(fos);
oos.writeObject(P3);
oos.close();

I closed the file and opened again because that’s what the original program will do, will record new indefinite objects times. The reading code is as follows, where products is a ArrayList<Produto>:

produtos.add((Produto)ois.readObject());
produtos.add((Produto)ois.readObject());
produtos.add((Produto)ois.readObject());

In the execution of this code only the first object is saved. Why this happens?

  • No need to close the file itself (fos) in addition to the stream (oos) at each cycle?

  • 1

    @epx It’s been a while since I’ve programmed in Java, but from what I remember when I closed a Stream it propagates it to the other streams it depends on (i.e. the oos will close the fos automatically).

  • Blz, the real problem was found and answered

2 answers

4


In accordance with this question in the SOEN, the problem is that the ObjectOutputStream writes a header (header) in the file after writing the first object, which should not be written more than once. The proposed solution is to use the method reset between one script and another to allow more than one object to be written without re-adding the header.

However, in your particular case this should not work - since the file is being closed and opened again several times. Moreover, it would require logic to only include the header if the file is empty, which in addition complicated may not be possible without changing the "original program".

My suggestion is - with the FileInputStream still open - create a new ObjectInputStream each time reading an object:

produtos.add((Produto)(new ObjectInputStream(fis)).readObject());
produtos.add((Produto)(new ObjectInputStream(fis)).readObject());
produtos.add((Produto)(new ObjectInputStream(fis)).readObject());

Note that I did not close the ObjectInputStream created - because they would also close the FileInputStream original, which is not what you want. I still need to do some tests to see if this solution actually solves the problem, but I leave this suggestion as a starting point.

4

The problem is that the ObjectOutputStream writes a header to the file. When you open new output streams this header is written several times in the middle of the file.

The classic solution would be to leave the ObjectOutputStream open (which may not be desirable). A second alternative would be to open several ObjectInputStreams as per @mgibsonbr’s response; each of them reads a header (however, as he himself pointed out this may have implications; I get a little uncomfortable not closing resources).

However, in an answer in SOEN the user Andreas_d pointed out a very interesting solution involving overwriting the method writeStreamHeader() with a call to reset().

public class AppendingObjectOutputStream extends ObjectOutputStream {

   public AppendingObjectOutputStream(OutputStream out) throws IOException {
      super(out);
   }

   @Override
   protected void writeStreamHeader() throws IOException {
      reset();
   }
}

Logic of use (adaptation of the original answer):

Check whether the file exists or not, and then ask stream adequate:

In case the file exists we are "appending" and do not want a header:

ObjectOutputStream oos = new AppendingObjectOutputStream(fos); 

In case the file does not exist we need a header:

ObjectOutputStream oos = new ObjectOutputStream(fos); 

You can even encapsulate this logic in a method:

// Esboço; no código real trate exceções
public ObjectOutputStream openStream(File f) throws Exception {
   ObjectOutputStream oos = null;
   if (f.exists()) {
      FileOutputStream fos = new FileOutputStream(f, true);
      oos = new AppendingObjectOutputStream(fos);
   } else {
      FileOutputStream fos = new FileOutputStream(f);
      oos = new ObjectOutputStream(fos);
   }
   return oos;
}

And the use of stream is transparent:

File f = new File("files\\Produtos.dat"); 
ObjectOutputStream oos = openStream(f); // Produtos.dat pode existir ou não
oos.writeObject(p);
oos.close();

oos = openStream(f); // Produtos.dat existe, apenda
oos.writeObject(p2);
oos.close();

// Versão Java 7 com try-with-resources
try (ObjectOutputStream oos = openStream(f)) {
   oos.writeObject(p3);
}

P.S. The JEP 187 is exactly researching failures and possible improvements in the Java Serialization mechanisms. Maybe something interesting comes out of this research effort.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.