This question already has an answer here:
StreamCorruptedException: invalid type code: AC
(1 answer)
Closed 5 years ago.
I was trying out a program that was given in the exercise at the end of the chapter 'Serialization'.
The program requires me to declare a class Person which encapsulates only two data members of type Name and Address , which are also classes.
Then I have to take a series of names and addresses from the keyboard , create objects and write them to the file.
However , if the FILE ALREADY EXISTS then the objects must be APPENDED to the existing file.
My program runs perfectly for the first time but for the second time , when I try to read back the appended records , I get an Exception
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1374)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at Trial.main(Trial.java:66)
I did my bit of research on this and found that the StreamHeader can be written ONLY ONCE and appending corrupts it.
What is the way around it ???
The Object Writing Code is:
try(ObjectOutputStream stream = new ObjectOutputStream(new BufferedOutputStream(Files.newOutputStream(filePath,WRITE,CREATE,APPEND)))) {
for(int i = 0;i<name.length;i++) {
Person aPerson = new Person(name[i],address[i]);
System.out.println(aPerson);
stream.writeObject(aPerson);
stream.reset();
aPerson = null;
}
System.out.println("Writing Complete");
Yes, I've had this problem myself before... it is not possible, unfortunately.
What you could do is to place your objects into a List and persist the full list at a time. As the list is an object it can persisted just as easily. I know this is terrible as this require the entire contents to be read into memory, but it is the only way as far as I know.
The other option (which I recommend) is that you use something like JSon to commit your data. GSon works quite well for this purpose. You can then simply marshall and unmarshall your objects which can be committed to a text file. It's very easy to do as a single line of code is required to go either way (object to JSon-string and vice versa).
This works. So debug your program and see why it doesn't. Probably don't call reset()
public class ClassTest {
public static void main(String a[]) throws Exception {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:/temp/foo.txt"));
oos.writeObject(new Test("foo", "bar"));
oos.writeObject(new Test("baz", "brr"));
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:/temp/foo.txt"));
System.out.println(ois.readObject());
System.out.println(ois.readObject());
ois.close();
}
}
class Test implements Serializable {
private String fld1;
private String fld2;
public Test(String v1, String v2) {
this.fld1 = v1;
this.fld2 = v2;
}
#Override
public String toString() {
return "Test [fld1=" + fld1 + ", fld2=" + fld2 + "]";
}
}
Related
I have an ArrayList of Employee objects where Employee class implements Serializable. I am using this code to write lists to a file:
ArrayList<Employee> empList = new ArrayList<>();
FileOutputStream fos = new FileOutputStream("EmpObject.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// write object to file
empList .add(emp1);
empList .add(emp2);
oos.writeObject(empList);
empList .add(emp3);
oos.writeObject(empList);
}
If I try to de-serialize it I am just getting first two objects not the 3rd one. Can anyone please try why is it?
edit1: If I add all elements at once everything is fine but not the way I did first. What is the difference?
ArrayList<Employee> empList = new ArrayList<>();
FileOutputStream fos = new FileOutputStream("EmpObject.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
// write object to file
empList .add(emp1);
empList .add(emp2);
empList .add(emp3);
oos.writeObject(empList);
}
After this I have 3 elements
As GhostCat and uaraven already mentioned reset does not what you are expecting it to do and you should have a look at a tutorial on serialization and maybe consider using sth. else if this isn't fitting your use case.
Your code could look as follows if creating a new FileOutputStream:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class SerializationTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
String path = "EmpObject.ser";
ArrayList<Employee> empList = new ArrayList<>();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
empList.add(emp1);
empList.add(emp2);
oos.writeObject(empList);
empList.add(emp3);
// Create a new FileOutputStream to override the files content instead of appending the new employee list
oos = new ObjectOutputStream( new FileOutputStream(path));
oos.writeObject(empList);
ObjectInputStream objectinputstream = new ObjectInputStream(new FileInputStream(path));
List<Employee> readCase = (List<Employee>) objectinputstream.readObject();
System.out.println(readCase);
}
}
What happens with your code:
you write the list into the file, with two entries
you reset the stream
you write the list again, with three entries
Thus your file contains two values, yes. Two lists, one with 2, one with 3 entries.
In other words: reset() doesn't reset what has been written to the file! You wrote one list with two entries. You are only resetting the information about stored objects, so that emp1 and emp2 get serialized completely again. Without the call to reset, the JVM would understand that it doesn't need to fully serialize emp1 and emp2 again.
Meaning: by default the JVM compresses the amount of data to transmit. It remembers which objects where already written, and instead of writing them repeatedly, it only writes something like "object X that was serialized earlier on comes again" into the stream.
So: I think you simply do not understand the point of the reset() method. Solution: read a small tutorial, like the one from tutorialspoint.
Edit given the latest comment by the OP:
What you ask for isn't possible in this way. You are writing list objects. That means that all entries of that list at that point get written to the file. The JVM remembers "that list has been written already", so it will not write it again, even when its internal state changed in the meantime.
Basically ObjectOutputStream remembers objects that are written to it. If the same object (by reference) is written again, it is not serialized, but rather a reference to previous serialized data is written to stream. reset() method cleans up internal data structures of ObjectOutputStream and allows you to write the same object again. reset() does not discard data already written to the stream.
If you try to deserialize your stream into two ArrayLists, you'll get one with two elements and one with three elements.
If you remove call to reset() method, then you will get two array lists with two elements (one actually serialized, and another as a reference to the previous serialized instance)
I'm stuck on this program I'm making for school. Here's my code:
public static void experiencePointFileWriter() throws IOException{
File writeFileResults = new File("User Highscore.txt");
BufferedWriter bw;
bw = new BufferedWriter(new FileWriter(writeFileResults, true));
bw.append(userName + ": " + experiencePoints);
bw.newLine();
bw.flush();
bw.close();
FileReader fileReader = new FileReader(writeFileResults);
char[] a = new char[50];
fileReader.read(a); // reads the content to the array
for (char c : a)
System.out.print(c); // prints the characters one by one
fileReader.close();
}
The dilemma I'm facing is how can I sort new scores with the scores in writeFileResults by the numerical value of int experiencePoints? If you're wondering about the variables userName is assigned by a textfield.getText method, and an event happens when you press one of 36 buttons which launches a math.Random statement with one of 24 possible outcomes. They all add different integer numbers to experiencePoints.
Well, I don't want to do your homework, and this does seem introductory so I'd like to give you some hints.
First, there's a few things missing:
We don't have some of the variables you've given us, so there is no type associated with oldScores
There is no reference to userName or experiencePoints outside this method call
If you can add this information, it would make this process easier. I could infer things, but then I might be wrong, or worse yet, have you learn nothing because I did your assignment for you. ;)
EDIT:
So, based on extra information, you're data file is holding an "array" of usernames and experience values. Thus, the best way (read: best design, not shortest) would be to load these into custom objects then write a comparator function (read: implement the abstract class Comparator).
Thus, in pseudo-Java, you'd have:
Declare your data type:
private static class UserScore {
private final String name;
private final double experience;
// ... fill in the rest, it's just a data struct
}
In your reader, when you read the values, split each line to get the values, and create a new List<UserScore> object which contains all of the values read from the file (I'll let you figure this part out)
After you have your list, you can use Collections#sort to sort the list to be the correct order, here would be an example of this:
// assuming we have our list, userList
Collections.sort(userList, new Comparator<UserScore>() {
public int compare(UserScore left, UserScore right) {
return (int)(left.getExperience() - right.getExperience()); // check the docs to see why this makes sense for the compare function
}
}
// userList is now sorted based on the experience points
Re-write your file, as you see fit. You now have a sorted list.
I'd like to know why my program is reading only 1. element of written objects.
I have 2 classes:
public class Sheet implements Serializable{
int something1;
String something2;
}
next one:
public class Book implements Serializable{
ArrayList<Sheet> menu = new ArrayList<Sheet>();
public void newSheet(Sheet temp)
{ menu.add(temp);}
}
Saving Book (in class main Book is static Book Libro = new Book();)
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream ("libro.obiekt"));
out.writeObject(Libro);
out.close();
and reading:
ObjectInputStream in = new ObjectInputStream(new FileInputStream("libro.obiekt"));
Libro = (Book) in.readObject();
in.close();
When I do this, while having for example: 5 objects in ArrayList inside Libro, I can read only first one, while other 4 would be NULL objects....
Any idea what am I doing wrong?
You can only read one object from file (serialized).
The reasons:
Each time you write object to file. you are overwritting it. so you
can only get the last object written.
even if you do set append to true
FileOutputStream fout = new FileOutputStream(new File(file),true);
//setting the append to true
deserializing will cause
java.io.StreamCorruptedException: invalid type code
To overcome it:
1. You could put all your objects in a list and write it as a whole (your arraylist).
serialize list of objects as a whole and deserialize it.
2. you can write each object in different file and read from it.
I have some input that I add to a serialized object.
Now when I read the serialized object, I want to check if it exists... If not loop till it has a value in it.
How do i modify the deserialization function to handle that.
There is basically a delay in populating my serializable object. So in the meantime if i were to read that object, it is going to be empty. I want to put a check to read only when it has data in it. if not it should wait till it has some data
public String _displayResults(){
String SomeData = "";
try {
FileInputStream fis = new FileInputStream("SomeDataobj");
ObjectInputStream ois = new ObjectInputStream(fis);
SomeData = (String)ois.readObject();
ois.close();
}
catch(Exception e) {
System.out.println("Exception during deserialization: ");
}
return SomeData;
}
What I tried:
added a wait condition for 2 secs for 10 times... Is there a cleaner way.
while ( ois.readObject().toString().equalsIgnoreCase("") && i <10){
Thread.sleep(2000);
i++;
}
Java provides an API called Externalizable, which allows you to customize the (de) serialization. Serialiazable is marker interface and that indicates the object can be wrote to output stream. Externalizable provides two methods readExternal() and writeExternal() where you can override the behavior.
Your question is not so clear about what you want to achieve, so I am not sure if the above information is helpful for you
I am trying to read info from a file and create objects out of that information. Every 6 or so lines of the file is a different unit, meaning that the first set of lines are relevant to object A, the next set to object B, and so on.
I can read from the file and create my object just fine--for the first set. My problem is that I don't know how to get the reader to pick up from the spot it left off at when creating the next object...
(Note: the read() method which creates the file is part of the new object being created, not in a main() or anything like that). Here are the relevant bits of code:
The driver:
public class CSD{
public static void main (String[] argv){
Vector V=new Vector(10);
CoS jon=new CoS();
jon.display();
}//end main
}
which calls CoS, whose constructor is:
public CoS(){
try{
String fileName=getFileName();
FileReader freader=new FileReader(fileName);
BufferedReader inputFile=new BufferedReader(freader);
this.read(inputFile);
setDegree(major);
setStatus(credits);
} catch(FileNotFoundException ex){
}//end catch
}
Which calls both read() and getFileName():
public void read(BufferedReader inputFile){
try{
int n;
super.read(inputFile);
String str=inputFile.readLine();
if (str!=null){
n=Integer.parseInt(str);
setCredits(n);
str=inputFile.readLine();
setMajor(str);
}//end if
}catch(IOException ex){}
}//end method
public String getFileName() {
Scanner scan = new Scanner(System.in);
String filename;
System.out.print("Enter the file name and path ==> ");
filename = scan.nextLine();
System.out.println("");
return filename;
}
Thanks in advance, guys!
Why not use ObjectInputStream and ObjectOutputStream? Or any kind of real serialization?
javadoc: http://docs.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html
example code: http://www.javadb.com/writing-objects-to-file-with-objectoutputstream
Basically, since you write your objects to a file and want to take care of the lines where they are located, I'll suggest a few other serialization alternatives.
One is the Object * Stream - you create a ObjectStream on a File and just write objects thru it. Later when you read, you read the objects in the reverse order you wrote them and they will come back just as you wrote them.
Another is to implement Serializable. Remember that transient keyword? Use it on fields you do not want to save to the file.
And then there's the raw "by hand" approach where you save only the things you want to save and reconstruct the objects later by passing these initialization values to their constructor. Kinda like people suggested that you make the file line a argument to the ctor :)
EDIT:
guess writing with Object*Streams requires you to implement Serializable or Externalizable.
but if the example code isn't clear enough, ask :)