ObjectOutputStream only saves the first object

5

I'm trying to manipulate a file in Byte with Java. In writing 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, it will write new objects indefinitely times. The read 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 does this happen?

    
asked by anonymous 08.02.2014 / 03:30

2 answers

4

As per this question in SOEN , the problem is that ObjectOutputStream writes a header ) in the file after writing the first object, which should not be written more than once. The proposed workaround is to use the reset between one write and another, to allow more than one object to be written without retyping the header.

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

My suggestion is - with FileInputStream still open - create a new ObjectInputStream each time you read 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 testing to see if this solution actually solves the problem, but I leave that suggestion as a starting point.

    
08.02.2014 / 03:43
4

The problem is that 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 workaround would be to leave% open% (which may not be desirable). A second alternative would be to open multiple ObjectOutputStream s according to @mgibsonbr; each of them reads a header (but as he 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 ObjectInputStream method with a call to writeStreamHeader() .

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 original response):

Check whether the file exists or not, then instantiate the appropriate stream :

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 into 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 becomes 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);
}

PS JEP 187 is exactly searching for faults and possible improvements to the Serialization mechanisms of Java. Maybe there is something interesting about this research effort.

    
08.02.2014 / 03:45