Reputation: 15
I have a trouble with my java project. After several searches, i'm still blocked.
I have a class named ListFromFile
that extends ArrayList
:
public class ListFromFile<T> extends ArrayList<T> implements Serializable {
private String listFile;
public ListFromFile() {
this.listFile = null;
}
public ListFromFile(String file) {
this.listFile = file;
}
public void loadDataFromFile() { // Deserialize from file
try {
FileInputStream fileInput = new FileInputStream(this.listFile);
if ( fileInput.read() == -1 ) { // If file is empty
this.saveDataInToFile();
} else {
ObjectInputStream objectInput = new ObjectInputStream(fileInput);
this.addAll((ArrayList) objectInput.readObject());
objectInput.close();
}
fileInput.close();
} catch ( IOException | ClassNotFoundException e ) {
e.printStackTrace();
}
}
public void saveDataInToFile() { // Serialize the ArrayList
try {
FileOutputStream fileOutput = new FileOutputStream(this.listFile, true);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(this);
objectOutput.flush();
objectOutput.close();
fileOutput.close();
} catch ( IOException e ) {
e.printStackTrace();
}
}
}
In my main class BZ2MServer
, i've created some objects with ListFromFile :
public class BZ2MServer {
private static ListFromFile<Specialite> specialites = new ListFromFile<Specialite>("liste_specialites.txt");
private static ListFromFile<Module> modules = new ListFromFile<Module>("liste_modules.txt");
private static ListFromFile<Professeur> professeurs = new ListFromFile<Professeur>("liste_professeurs.txt");
private static ListFromFile<Etudiant> etudiants = new ListFromFile<Etudiant>("liste_etudiants.txt");
private static ListFromFile<Note> notes = new ListFromFile<Note>("liste_notes.txt");
public static void main(String[] args) {
specialites.loadDataFromFile();
}
}
When the application starts, it loads the lists saved in files. That's why i execute saveDataInToFile()
inside that loadDataFromFile()
method.
By this way, the files should contain empty ArrayList at the first time we launch the application.
The result is that for the first launch, there is no issue. However, after this, i always have this from the compiler :
java.io.StreamCorruptedException: invalid stream header: ED000573
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:804)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at bz2m.list.ListFromFile.loadDataFromFile(ListFromFile.java:31)
at bz2m.server.BZ2MServer.main(BZ2MServer.java:22)
I have tested this in the main of BZ2MServer
:
public static void main(String[] args) {
Specialite test = new Specialite(1, "Test");
specialites.add(test2);
specialites.saveDataInToFile();
}
Then, i removed the previous code, used LoadDataFromFile()
to get the previous datas. And i got the error. Then, i removed that condition in ListFromFile
class :
if ( fileInput.read() == -1 ) {
this.saveDataInToFile();
}
And it worked. However, that condition was necessary in the case the file is empty. Without it, and if the file is empty, i get this :
java.io.EOFException
at java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2325)
at java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:2794)
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:801)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at bz2m.list.ListFromFile.loadDataFromFile(ListFromFile.java:31)
at bz2m.server.BZ2MServer.main(BZ2MServer.java:22)
I hope that i have give you all the information you need to help me. If you need, i can upload the entire project (not huge).
Thank you !
Upvotes: 1
Views: 3481
Reputation: 19506
The serialization methods you're using includes a magic number verification check that it uses to determine whether your data is valid or not. So if it's anything other than what it expects, it will throw an exception telling you that your input does not conform to its serialization standards.
In this case, it expects the first two bytes to be AC ED
followed by a version 00 05
. You can see them in the list of constants here.
The invalid stream header: ED000573
indicates that the first 4 bytes of the input that it received is ED 00 05 73
. If you open it in a hex viewer, you might actually be confused: the first bytes starting at position 0 is indeed AC ED 00 05
, so what's the problem?
The reason why your load method fails is precisely because of that check you made:
if ( fileInput.read() == -1 ) {
this.saveDataInToFile();
}
This reads one byte, which increments the file pointer to the second byte in the file. Now when you pass your stream to the ObjectInputStream
for loading, it will read the first 4 bytes from where the current pointer is, see ED 00 05 73
and then fail. You can verify this yourself by looking at the next byte after in your viewer.
If you want to check whether your file is not empty, instead of reading a byte to check whether there are bytes or not, just query the channel for its length directly:
if (fileInput.getChannel().size() == 0) {
// empty file
}
Upvotes: 4