1

I want to add lots of data to a file. I defined the HYB class since my object contains ofdifferent types of data (String and byte[]). I used ObjectOutputStream and ObjectInputStream to write and read from the file. But my code does not print the expected result. To write my code I used code in the following pages: How can I append to an existing java.io.ObjectStream?

ClassCastException when Appending Object OutputStream

I try to debug my code and found the problem but I could not. This is my code:

import java.io.*;
import java.io.BufferedOutputStream;
import java.util.*;

public class HYB implements Serializable
 {
private static final long serialVersionUID = 1L;
private List<byte[]> data = new ArrayList<>();

public void addRow(String s,byte[] a)
{
    data.add(s.getBytes()); // add encoding if necessary
    data.add(a);
}

@Override public String toString()
{
    StringBuilder sb = new StringBuilder();
    synchronized (data)
    {
        for(int i=0;i<data.size();i+=2)
        {
            sb.append(new String(data.get(i)));
            sb.append(Arrays.toString(data.get(i+1))+"\n");
        }
    }
    return sb.toString();
}

private static void write(File storageFile, HYB hf)
        throws IOException {
               ObjectOutputStream oos = getOOS(storageFile);
               oos.writeObject(hf);
               oos.flush();
               oos.close();
}

public static ObjectOutputStream getOOS(File file) throws IOException
{

    if (file.exists()) {
        return new AppendableObjectOutputStream(new FileOutputStream(file, true));
    } else {
        return new ObjectOutputStream(new FileOutputStream(file));
    }
}



 private static ObjectInputStream getOIS(FileInputStream fis)
        throws IOException {
               long pos = fis.getChannel().position();
               return pos == 0 ? new ObjectInputStream(fis) : 
                         new AppendableObjectInputStream(fis);
}

private static class AppendableObjectOutputStream extends
ObjectOutputStream {

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

  @Override
  protected void writeStreamHeader() throws IOException {

  }
 }

private static class AppendableObjectInputStream extends ObjectInputStream {

    public AppendableObjectInputStream(InputStream in) throws IOException {
        super(in);
    }

    @Override
    protected void readStreamHeader() throws IOException {
        // do not read a header
    }
}



public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException
{

    File x=new File ("test");


    HYB hf1 = new HYB();
    hf1.addRow("fatemeh",new byte[] {11,12,13});
    hf1.addRow("andisheh",new byte[] {14,15,16});

    write(x,hf1);


    HYB hf = new HYB();
    hf.addRow("peter",new byte[] {1,2,3});
    hf.addRow("jaqueline",new byte[] {4,5,6});
    write(x,hf);


    FileInputStream fis = new FileInputStream(x);
    HYB hf2 = (HYB) getOIS(fis).readObject();
    System.out.println(hf2);
  }
}

expected results:

fatemeh[11, 12, 13]
andisheh[14, 15, 16]
peter[1, 2, 3]
jaqueline[4, 5, 6]

actual results:

fatemeh[11, 12, 13]
andisheh[14, 15, 16]
Community
  • 1
  • 1
user3487667
  • 519
  • 5
  • 22

2 Answers2

2

Writing the two HYB objects to the ObjectOutputStream doesn't merge them into a single HYB object; the ObjectOutputStream still contains two HYB object, of which your code reads one. If you did a second call to readObject(), the second one would be retrieved and could be printed to the screen. So you could just wrap the readObject() and println() calls in a loop that reads/writes until there's nothing else to read from the stream.

Tim
  • 2,027
  • 15
  • 24
  • You can use a `while` loop: `ObjectInputStream ois = getOIS(fis); while (ois.available() > 0) { HYB hf2 = (HYB) ois.readObject(); System.out.println(hf2); }`. This works because your application knows that it writes all of its content before it starts reading; if you weren't sure of that (e.g. if you were reading from a Socket), then you could just use `while (true)` instead and then catch the `EOFException` that will get thrown once you try to read after you've read the last object (or if the Socket is prematurely closed). – Tim Jul 21 '14 at 17:55
  • You said catch EOFException. Is there any other way to solve this problem? – user3487667 Jul 21 '14 at 18:59
  • I suggested two ways: use [ObjectInputStream.available()](http://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html#available()) to test whether you've reached the end of the stream, or read until an `EOFException` is thrown and use that to determine that you've reached the end of the stream. Catching the `EOFException` isn't inherently a bad idea, and if you can't guarantee that all writing will happen before you start reading then it's your only choice. But for what you've described, either appraoch will work. The bigger question is, why are you opposed to exception handling? – Tim Jul 21 '14 at 19:06
  • Thank You.I think catching an exception is bad idea.But I found the following link explains why we should catch this exception. [link](http://stackoverflow.com/questions/18451232/eofexception-how-to-handle) – user3487667 Jul 21 '14 at 20:55
  • Catching exceptions is actually a good idea, but only at a place where you can meaningfully handle them (i.e. take an action in response). Lots of people do a bad job of dealing with exceptions because they catch them in code that doesn't know what to do with them (usually because it's too deep in the call stack, because they're afraid of allowing the exception to be thrown from their own code), so they log them to Log4J and then continue as though nothing went wrong. – Tim Jul 21 '14 at 21:07
  • But you're right that you should use method calls to test for conditions that would throw exceptions whenever possible. Sometimes that's not an option (for example, when doing asynchronous I/O from a Socket, it's not always possible to know when you're done reading from the Socket until the sender closes the Socket), and in those cases catching an exception may be your best option. So try to avoid exception-based program control when there's another option, but don't be afraid to use exceptions when there isn't another good option. – Tim Jul 21 '14 at 21:10
0

You are writing two HYB objects to the stream, but only reading one out.

You need to readObject() twice.

Jamie Cockburn
  • 7,379
  • 1
  • 24
  • 37