I'm currently trying to save and load multiple instances of a class of type 'Player' via serialization. (This is for an assignment as an fyi).
The way the process currently works is I run the class via an ObjectOutputStream.writeObject(Player), this seems to work as I get the text file with what appears to be class data.
The problem I'm currently having is when I reverse and load the class, I'm unable to cast the object back to a player object, it is throwing an exception, however I'm not currently knowledgeable enough to figure out the exact exception.
Please find below the functions.
Save function:
public void savePlayers(ArrayList<Player> p)
{
FileOutputStream fout = null;
ObjectOutputStream oos = null;
try
{
fout = new FileOutputStream("Player.txt");
oos = new ObjectOutputStream(fout);
for(Player player: p)
{
oos.writeObject(p);
}
fout.close();
oos.close();
}
catch(Exception e)
{
System.out.println("Error is: " + e);
}
finally
{
closeStreams(fout, oos);
}
}
Load Function:
public ArrayList<Player> loadPlayers()
{
ArrayList<Player> loadedList = new ArrayList<Player>();
FileInputStream fis;
ObjectInputStream ois;
try
{
fis = new FileInputStream("Player.txt");
ois = new ObjectInputStream(fis);
while(true)
{
System.out.println("Entered loop"); //testing
Object obj = ois.readObject();
System.out.println("Read object done"); //testing
Player p = (Player)obj;
System.out.println("Casted player"); //The line here doesn't run, prints out error from exception instead and exits loop
loadedList.add(p);
System.out.println("Loop iterated");
}
}
catch(EOFException eof)
{
}
catch(Exception e)
{
System.out.println("Exception here");
}
}
Is there a better way to save the classes? Am I doing something wrong when casting?
change to
oos.writeObject(player);
and the moment you are writing the whole ArrayList multiple times
Related
I want to append multiple object at the end to the same binary file using ObjectOutputStream
But when I run the following code more than one time I get the exception
java.io.StreamCorruptedException: invalid type code: AC
The question is
Is there any headers things that I should know to APPEND OBJECTS at the end of the file in java?
package sourcepackage;
import sourcepackage.persons.Person;
import sourcepackage.persons.Student;
import java.io.*;
public class MainClass {
public static void main(String[] args) {
Person mahmoud_kanbar = new Student(21, 224466, "Mahmoud Kanbar", "ITE");
try {
FileOutputStream out = new FileOutputStream("Hello.dat", true);
ObjectOutputStream objectOut = new ObjectOutputStream(out);
objectOut.writeObject(mahmoud_kanbar);
objectOut.close();
out.close();
FileInputStream in = new FileInputStream("Hello.dat");
ObjectInputStream objectIn = new ObjectInputStream(in);
while (in.available() != 0) {
Person hi = (Person) objectIn.readObject();
hi.printInfo();
}
objectIn.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
I was searching for decades about a solution to this problem and I couldn't find anything
I want to append objects just like the c++ do
You can append objects to the same ObjectOutputStream with writeObject() method. When reading, they are read in the same order they were written. Also, you may be getting that error because your stream is buffered and not written. You should use flush() method to make sure the buffer has been written to the file.
Let's write two objects to the same file and read them:
Person mahmoud_kanbar = new Student(21, 224466, "Mahmoud Kanbar", "ITE");
Person omid = new Student(18, 200000, "Omid Nejadabbasi", "ITE");
try {
FileOutputStream out = new FileOutputStream("Hello.dat", true);
ObjectOutputStream objectOut = new ObjectOutputStream(out);
objectOut.writeObject(mahmoud_kanbar);
objectOut.writeObject(omid);
objectOut.flush();
objectOut.close();
out.close();
FileInputStream in = new FileInputStream("Hello.dat");
ObjectInputStream objectIn = new ObjectInputStream(in);
Person newPerson= (Person) objectIn.readObject();
newPerson.printInfo();
newPerson= (Person) objectIn.readObject();
newPerson.printInfo();
objectIn.close();
in.close();
} catch (Exception e) {
System.out.println(e);
}
readObject() deserializes the next Object serialized into the stream.
I'm working on appending objects to a binary file. My file is:
File f=new File("person.dat");
I'm getting an error (java.io.StreamCorruptedException: invalid stream header: 79737200) when I attempt to open the binary file. As far as I can tell the program writes the data just fine, but as soon as I try reading from it, I get the above error. Any help is appreciated!
My Code to write:
AppendObjectOutputStream out = null;
try {
out = new AppendObjectOutputStream(new FileOutputStream(f, true));
out.writeObject(new Student(name, age));
out.flush();
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
out.close();
}
My class for making appendable:
public class AppendObjectOutputStream extends ObjectOutputStream {
public AppendObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {
reset();
}
}
My partial code for reading and adding objects to an ArrayList:
Course course = new Course();
Student st = null;
ObjectInputStream in = null;
try {
in = new ObjectInputStream(new FileInputStream("person.dat"));
try
{
while (true)
{
st = (Student) in.readObject();
course.addAccount(st); //adds student object to an ArrayList in
//class Course
}
}
catch (EOFException ex) {
}
}
catch (Exception ex) {
ex.printStackTrace();
} finally {
in.close();
}
UPDATE:
Current code to read but its not printing anything to screen:
try(ObjectInputStream ois = new ObjectInputStream(
new BufferedInputStream(Files.newInputStream(f))))
{
while (ois.available() > 0)
{
st = (Student) ois.readObject();
studentlist.addAccount(st);
System.out.println(st.getStudentNumber());
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
This is how I write to file:
Path f = Paths.get("person.dat");
try (ObjectOutputStream oos = new ObjectOutputStream(
new BufferedOutputStream(Files.newOutputStream(f, StandardOpenOption.APPEND))))
{
oos.writeObject(new Student(name,age));
}
catch(Exception ex)
{
ex.printStackTrace();
}
Rather than trying to fix your utility classes, I suggest to use the standard classes of the NIO.2 File API.
Try something like (untested):
Path personDataFilePath = Paths.get("person.dat");
// or Java 11:
// Path personDataFilePath = Path.of("person.dat");
try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(personDataFilePath, StandardOpenOption.APPEND)))){
oos.writeObject(new Student(name,age));
} catch (IOException ex) {
// do some error handling here
}
and to read the file, something like (untested):
List<Student> students = new ArrayList<>();
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(personDataFilePath)))){
while (ois.available() > 0){
students.add((Student) ois.readObject());
}
} catch (IOException ex) {
// do some error handling here
}
I have modified the code to work around making a file "appendable". I write a single arraylist object to the file (the arraylist holds a list of student objects). When I want to add a student, I read the object (arraylist) from the file, add my new student to the arraylist and write the arraylist back to the file. It is now working and my file does not have an append format.
Greeting,
I am working on a program that depends on p2p local network ,i create new peers by pressing run on the IDE , i want an array list to be shared between all the threads so i can modify on it.
the problem i have faced that if the first thread write on the serialization file the newly created threads can read this modification on the list, but if the last thread modify the list the first threads can't see this modification since they desesrialize the file once on the run button press.
is there any solution for this ?(Java)
code:
Peer peer = Peer.getInstance(portName, portNumber, "localhost", peers);
new Thread(peer::startHost).start();
peers.put(peer.getPort(), peer);
waitASecond();
serializePeers();
return peer;
Serialize :
private static void serializePeers() {
try {
FileOutputStream fos = new
FileOutputStream("peersList.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(peers);
oos.close();
fos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
Desirialize:
private static void deserializePeers() {
try {
FileInputStream fis = new FileInputStream("peersList.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
peers = (LinkedHashMap<Integer, Peer>) ois.readObject();
ois.close();
fis.close();
} catch (Exception e) {
System.out.println("This is the first peer connected to the network"); }
}
I'm trying to store an arraylist of a type I made, inside of a dat file so that the data isn't lost every time I close the program. I've never done anything with serialization before, from looking at other questions on this site I think it's what I want. Any help or insight is vastly appreciated!
ArrayList implements Serializable ,So you can serialize it. But remember that ArrayList is just a collection of items, so make sure that all the items are also serializable. Here is an example
import java.util.ArrayList;
import java.io.*;
public class ListSerExample {
public static void main(String[] args) {
ArrayList<String> lst = new ArrayList<>();
lst.add("a");
lst.add("b");
lst.add("c");
try (FileOutputStream fos = new FileOutputStream("foo.dat"); ObjectOutputStream oos = new ObjectOutputStream(fos);) {
oos.writeObject(lst);
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
ArrayList<String> deserialized= new ArrayList<>();
try (FileInputStream fis = new FileInputStream("foo.dat");
ObjectInputStream ois = new ObjectInputStream(fis);){
deserialized = (ArrayList) ois.readObject();
ois.close();
fis.close();
System.out.println("deserialized = " + deserialized);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
I am going to write multiple objects to a file and then retrieve them in another part of my code. My code has no error, but it is not working properly. Could you please help me find what is wrong about my code.
I read different codes from different websites, but none of them worked for me!
Here is my code to write my objects to a file:
MyClassList is an arraylist which includes objects of my class (which must be written to a file).
for (int cnt = 0; cnt < MyClassList.size(); cnt++) {
FileOutputStream fout = new FileOutputStream("G:\\address.ser", true);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(MyClassList.get(cnt));
}
I added "true" to the constructor of the outputstream, because I want to add each object to end of the file. Is that correct?
And here is my code to read the objects from the file:
try {
streamIn = new FileInputStream("G:\\address.ser");
ObjectInputStream objectinputstream = new ObjectInputStream(streamIn);
MyClass readCase = (MyClass) objectinputstream.readObject();
recordList.add(readCase);
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
}
It finally prints out just one object. Now, I don't know if I am not writing correctly or reading correctly!
Why not serialize the whole list at once?
FileOutputStream fout = new FileOutputStream("G:\\address.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(MyClassList);
Assuming, of course, that MyClassList is an ArrayList or LinkedList, or another Serializable collection.
In the case of reading it back, in your code you ready only one item, there is no loop to gather all the item written.
As others suggested, you can serialize and deserialize the whole list at once, which is simpler and seems to comply perfectly with what you intend to do.
In that case the serialization code becomes
ObjectOutputStream oos = null;
FileOutputStream fout = null;
try{
fout = new FileOutputStream("G:\\address.ser", true);
oos = new ObjectOutputStream(fout);
oos.writeObject(myClassList);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if(oos != null){
oos.close();
}
}
And deserialization becomes (assuming that myClassList is a list and hoping you will use generics):
ObjectInputStream objectinputstream = null;
try {
FileInputStream streamIn = new FileInputStream("G:\\address.ser");
objectinputstream = new ObjectInputStream(streamIn);
List<MyClass> readCase = (List<MyClass>) objectinputstream.readObject();
recordList.add(readCase);
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectinputstream != null){
objectinputstream .close();
}
}
You can also deserialize several objects from a file, as you intended to:
ObjectInputStream objectinputstream = null;
try {
streamIn = new FileInputStream("G:\\address.ser");
objectinputstream = new ObjectInputStream(streamIn);
MyClass readCase = null;
do {
readCase = (MyClass) objectinputstream.readObject();
if(readCase != null){
recordList.add(readCase);
}
} while (readCase != null)
System.out.println(recordList.get(i));
} catch (Exception e) {
e.printStackTrace();
} finally {
if(objectinputstream != null){
objectinputstream .close();
}
}
Please do not forget to close stream objects in a finally clause (note: it can throw exception).
EDIT
As suggested in the comments, it should be preferable to use try with resources and the code should get quite simpler.
Here is the list serialization :
try(
FileOutputStream fout = new FileOutputStream("G:\\address.ser", true);
ObjectOutputStream oos = new ObjectOutputStream(fout);
){
oos.writeObject(myClassList);
} catch (Exception ex) {
ex.printStackTrace();
}
Simple program to write objects to file and read objects from file.
package program;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TempList {
public static void main(String[] args) throws Exception {
Counter counter = new Counter(10);
File f = new File("MyFile.txt");
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(counter);
oos.close();
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois = new ObjectInputStream(fis);
Counter newCounter = (Counter) ois.readObject();
System.out.println(newCounter.count);
ois.close();
}
}
class Counter implements Serializable {
private static final long serialVersionUID = -628789568975888036 L;
int count;
Counter(int count) {
this.count = count;
}
}
After running the program the output in your console window will be 10 and you can find the file inside Test folder by clicking on the icon show in below image.
I think you have to write each object to an own File or you have to split the one when reading it.
You may also try to serialize your list and retrieve that when deserializing.
if you serialize the whole list you also have to de-serialize the file into a list when you read it back. This means that you will inevitably load in memory a big file. It can be expensive. If you have a big file, and need to chunk it line by line (-> object by object) just proceed with your initial idea.
Serialization:
LinkedList<YourObject> listOfObjects = <something>;
try {
FileOutputStream file = new FileOutputStream(<filePath>);
ObjectOutputStream writer = new ObjectOutputStream(file);
for (YourObject obj : listOfObjects) {
writer.writeObject(obj);
}
writer.close();
file.close();
} catch (Exception ex) {
System.err.println("failed to write " + filePath + ", "+ ex);
}
De-serialization:
try {
FileInputStream file = new FileInputStream(<filePath>);
ObjectInputStream reader = new ObjectInputStream(file);
while (true) {
try {
YourObject obj = (YourObject)reader.readObject();
System.out.println(obj)
} catch (Exception ex) {
System.err.println("end of reader file ");
break;
}
}
} catch (Exception ex) {
System.err.println("failed to read " + filePath + ", "+ ex);
}