5

I would like to ask the community what do you think about the following situation. The task is to write objects to a file. Which could be made by writing a list of objects to the file that I can read later so I have my objects again. Here, I would write practically ONLY ONE object to the file, namely the list (that may contain more objects).

But, the task seams to be to write separate objects to the file, which the method receives from a list. The objects can be whatever. (they must be serializable of course)

So I did:

public class TaskStream {
    public static void saveObjects(ArrayList<Object> al) {
        try {
            FileOutputStream fos = new FileOutputStream("outputFile", true);
            try {
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                for (Object o : al){
                    try {
                        oos.writeObject(o);
                        System.out.println("saved");
                    } catch (NotSerializableException e) {
                        System.out.println("An object was not serializable, it has not been saved.");
                        e.printStackTrace();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }

This works just fine.

But now, I'd like to read them. My first concept about it would be a kind of method, that reads objects until the file has objects, and I can save each of them to a list again (that's the task). So like Pseudo code:

for(Object o : fileToRead){ list.add(o) }

How would it be possible? I started to play around with the readObject method of the ObjectInputStream, but it seems to lead to a lot of errors.

Do you have any idea? Or what would be the best practice by such a task?


Thanks!

I tried your idea. The exact implementation:

public static ArrayList<Object> readObjects(){
    ArrayList<Object> al = new ArrayList<Object>();
    boolean cont = true;
        try {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("outputFile"));
            while(cont){
                  Object obj=null;
                try {
                    obj = ois.readObject();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
                  if(obj != null)
                     al.add(obj);
                  else
                     cont = false;
               }
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

 return al;
}    

To test the program I will write two objects into the file. I read the objects from the file and add them to a list. I iterate through this list and print out the content.

If I run the program the following happens (I deleted the outputFile, so the program can recreate it and do everything from scratch).

Result:

The two objects from the list will be successfully printed. But I receive this:

java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2598)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1318)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)    

...

I don't change anything, and I run the program again. Result:

The two objects from the list will be successfully printed. But I receive this:

java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1377)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)    

From now on, any rerun brings the same result.

If I repeat the whole process from the very beginning again (starting by deleting the outputFile) everything happens exactly the same (as expected).

Do you have ideas how to fix it? Thank you very much for the help!

Pritam Banerjee
  • 15,297
  • 10
  • 71
  • 92
user3435407
  • 799
  • 2
  • 12
  • 28
  • http://www.javapractices.com/topic/TopicAction.do?Id=57 might be interesting – Roy Wasse Dec 10 '14 at 20:01
  • yes, I've already read it, but there he writes a list to the file. Normally i would do the same, but the task is to write separate objects into the file... – user3435407 Dec 10 '14 at 20:04
  • What errors are you getting ? And can you post the code rather than the pseudo-code since right now it seems you're doing it right ... – vlatkozelka Dec 10 '14 at 20:11
  • Hi Vlatkozelka and Mitch, please see the edited post again, thx! – user3435407 Dec 10 '14 at 21:20
  • 1
    ok, so thanks for the idea with the boolean cont! For those, who have this problem too, i did catch the EOFException, that is ok then, and I gave up the idea to append to the file, so i deleted the argument "true" by creating the output. so i will do: when i want to append, first i read all info, put it into a list, add the extra info to the list, and write it into the file, if somebody has a better idea, please share, thx – user3435407 Dec 10 '14 at 23:31

9 Answers9

5

You're going to want to use FileInputStream and ObjectInputStream.

FileInputStream fis = new FileInputStream("outputFile");
ArrayList<Object> objectsList = new ArrayList<>();
boolean cont = true;
while (cont) {
  try (ObjectInputStream input = new ObjectInputStream(fis)) {
    Object obj = input.readObject();
    if (obj != null) {
      objectsList.add(obj);
    } else {
      cont = false;
    }
  } catch (Exception e) {
    // System.out.println(e.printStackTrace());
  }
}
MitchAman
  • 116
  • 5
2

The solution is pretty simple. Here you have to handle EOFException. To do so you have to modify your code as follows -

try {
    obj = ois.readObject();
} catch (EOFException e) {
    break;
}
Payel Senapati
  • 469
  • 3
  • 12
0

We've to used FileInputStream class method "available" method to check that given stream has data or bytes to read or not if data is not present then this method will return 0;

public static ArrayList<Object> getObjects(){

    ArrayList<Object> objects = new ArrayList<Object>(); 
    FileInputStream fis = new FileInputStream("outputFile");
    ObjectInputStream ois = new ObjectInputStream(fis);

    Object obj =null;

    boolean isExist = true;

    while(isExist){
        if(fis.available() != 0){
         obj = (A) ois.readObject();    
         objects.add(obj);
        }
        else{
        isExist =false;
        }
    }
    return objects;     
}
Ankit Chandora
  • 261
  • 3
  • 7
0

We can add all the object in a list and then serialize the list. Again we can deserialize the list and we can iterate over the list to get the objects , which we are looking for. It will require the use of below classes. FileOutputStream FileInputStream ObjectInputStream ObjectOutputStream

import java.io.Serializable;
import java.util.List;
import java.util.ArrayList;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;

    public class MultiObjectSerialization {
        static String file = "helloFruits.txt";
        static ObjectOutputStream os;
        static ObjectInputStream is;

        public static void main(String[] args) throws IOException,
                ClassNotFoundException {
            Apples a = new Apples(1, "apple");
            Mango m = new Mango(2, "Mango");

            List<Object> fruits = new ArrayList<>();
            fruits.add(a);
            fruits.add(m);
            writeToFile(fruits);
            readFile();

        }

        public static void writeToFile(List<Object> fruits) throws IOException {
            os = new ObjectOutputStream(new FileOutputStream(file));
            os.writeObject(fruits);
            os.close();

        }

        public static void readFile() throws ClassNotFoundException, IOException {
            is = new ObjectInputStream(new FileInputStream(file));
            List<Object> input = (List<Object>) is.readObject();
            List<Object> checkList = new ArrayList<>();
            // this will contain the list of the objects
            for (Object l : input) {
                checkList.add(l.getClass().getSimpleName());
                if (l instanceof Apples) {
                    Apples app = (Apples) l;
                    System.out.println(app.id);
                    System.out.println(app.name);
                }
                if (l instanceof Mango) {
                    Mango app = (Mango) l;
                    System.out.println(app.id);
                    System.out.println(app.name);
                }
            }
            System.out.println(checkList);

            is.close();
        }
    }

    class Apples implements Serializable {
        private static final long serialVersionUID = 1L;
        int id;
        String name;

        public Apples(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    class Mango implements Serializable {
        private static final long serialVersionUID = 1L;
        int id;
        String name;

        public Mango(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }


  The Output is ::
    1
    apple
    2
    Mango
    [Apples, Mango]
pushkars
  • 1
  • 2
0

I know the topic is old but i thing i know the solution to this. The reason you get

`'invalid type code: AC'`

is because after you write one object and you try to read it , the ObjectInputStream is trying to read the info your ObjectOutputStream wrote. That's how serialization works in general. The problem on your code is that a new ObjectInputStream is getting created and tries to read back from an old ObjectOutputStream and it finds out that they don't have the same serial code so you get this error.

I found a solution at another topic posted some time ago , check here :stackoverflow solution

What he is doing is that he is overridng the streamWriter which "tricks" the ObjectInputStream to believing that he can read the ObjectOutputStream.

Hope thats helpfull. Peace out!

0
import java.io.*;
import java.util.*;
class ObjectReadWrite implements Serializable, Comparable <ObjectReadWrite>
{
    int no;
    String name;
    ObjectReadWrite(int i,String s)
    {
        this.no=i;
        this.name=s;
    }
    public String toString()
    {
        return "TP Data : "+this.no+":"+this.name;
    }
    public int compareTo(ObjectReadWrite a1)
    {
        return this.name.compareTo(a1.name);
    }
    public static void main(String args[]) throws Exception
    {
        TreeSet<ObjectReadWrite> aw = new TreeSet<ObjectReadWrite>();
        aw.add(new ObjectReadWrite(1,"ABC"));
        aw.add(new ObjectReadWrite(2,"DDF"));
        aw.add(new ObjectReadWrite(3,"DAF"));
        aw.add(new ObjectReadWrite(4,"DCF"));

        //Writing Objects From TreeSet
        ObjectOutputStream os=new ObjectOutputStream(
                    new FileOutputStream(
                    new File("Test.dat")));
        os.writeObject(aw);
        os.close();



        //Reading Objects into TreeSet
        TreeSet ar = new TreeSet();
        ObjectInputStream is=new ObjectInputStream(
                    new FileInputStream(
                    new File("Test.dat")));

        ar=(TreeSet)is.readObject();
        is.close();


        Iterator ir = ar.iterator();
        while(ir.hasNext())
        {
            System.out.println((ObjectReadWrite)ir.next());
        }

    }
}
0
FileInputStream fileStream = new FileInputStream("file.txt");
        // Creates an ObjectInputStream
ObjectInputStream input = new ObjectInputStream(fileStream);
        // Reads the objects
   while (fileStream.available() != 0) {
      Object human = (Human) input.readObject();
       if (human != null)
        System.out.println(human);
}
0

I was trying to do some of these snippets code but most of them didn't work out for me. But @pushkars's code worked well, instead of making a while loop to get many objects, you can simply write and read a single List of objects and handle directly the list instead of reading or writing many objects.

See the code of my static IOMannager class:

public static class IOMannager {
    
    private static List<Produto> lista_produtos = new ArrayList<Produto>();
        
    public static void ler() {
            
        ObjectInputStream in = null;
        try{
            in = new ObjectInputStream(new FileInputStream("produtos.txt"));
            Object obj = in.readObject();
            in.close();
            lista_produtos = (ArrayList<Produto>) obj;
        }
        //catches goes here....
    }
}

Now I have all objects into my List lista_produtos and can deal with them as I wish.

Thanks @pushkars

Peter Csala
  • 4,906
  • 7
  • 11
  • 29
0

this one worked for me:

try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
listeSolutions.clear();
Solution s;
while (true) {
try {
s = (Solution) ois.readObject();

listeSolutions.add(s);
} catch (Exception e) {
break; }
}
ois.close();
} catch (Exception e) {
e.printStackTrace(); 
}
Fath
  • 29
  • 6