Serialization:java.io.StreamCorruptedException: invalid stream header: 0AACED00
Asked Answered
F

2

6

I'm a student practicing my File IO skills and I am coming up against a problem with reading Objects from a file using ObjectInputStream. The code is consistently throwing an InvalidClassException and I can't find how the code is throwing it online or by trial and error. Here's my code:

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ReadFromFile {
String filename;
List<Object> os;

public ReadFromFile(String filename) {
    this.filename = filename;
    os = new ArrayList<>();
}

public Object[] readObject() {
    try {
        FileInputStream fis = new FileInputStream(filename);
        ObjectInputStream ois = new ObjectInputStream(fis);
        System.out.print("reading\n");
        while (true) {
            os.add(ois.readObject());
            System.out.print("read one\n");
        }
    } catch (EOFException e) {
        return os.toArray();
    } catch (FileNotFoundException e) {
        System.out.print("File not found\n");
        return os.toArray();
    } catch (ClassNotFoundException e) {
        System.out.print("Class not found\n");
        return os.toArray();
    } catch (StreamCorruptedException e) {
        System.out.print("SC Exception\n");
        e.printStackTrace();
        return os.toArray();
    } catch (InvalidClassException e) {
        e.printStackTrace();
        System.out.print("IC Exception\n");
        return os.toArray();
    } catch (OptionalDataException e) {
        System.out.print("OD Exception\n");
        return os.toArray();
    } catch (IOException e) {
        System.out.print("IO Exception\n");
        return os.toArray();
    }
}
} 

I wrote all of the separate catch blocks to figure out what Exception was being thrown and it always throws the InvalidClassException.

Here also is my Tree Class:

import java.io.Serializable;

public class Tree implements Serializable {
private static final long serialVersionUID = -310842754445106856L;
String species;
int age;
double radius;

public Tree() {
    this.species = null;
    this.age = 0;
    this.radius = 0;
}
public Tree(String species, int age, double radius) {
    this.species = species;
    this.age = age;
    this.radius = radius;
}

public String toString() {
    return species + ", age: " + age + ", radius: " + radius;
}
}

And here is my write to file function:

public boolean write(Object object) {
    try {
        File f = new File(filename);
        FileOutputStream fos = new FileOutputStream(f,true);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(object + "\n");
        oos.close();
    } catch (FileNotFoundException e) {
        System.out.print("File Not Found\n");
        return false;
    } catch (IOException e) {
        System.out.print("IOException\n");
        return false;
    }
    return true;
}

Your knowledge is appreciated...

Stack trace:

SC Exception
java.io.StreamCorruptedException: invalid stream header: 0AACED00
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:806)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:299)
at ReadFromFile.readObject(ReadFromFile.java:17)
at WriteAndRecord.main(WriteAndRecord.java:21)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

Process finished with exit code 0

Felske answered 9/11, 2015 at 23:33 Comment(11)
Also post a stacktrace please. That's the best source to start pinpointing the error.Reremouse
What has the class Tree got to do with the source?Vampire
Is that one program? Class Tree should be available in classpath to be able deserialize object to it.Irma
To expand on @Mr.V.'s comment, Tree must be visible to both the serializer and the deserializer. "read one" is never printed, is it?Stichometry
I don't know what a stacktrace is, sorry. The 'Tree' Class could be part of the problem. These are all classes in a project and because the 'Tree' class is public it should be visible to anything, right? And, yes, "read one" is never printed.Felske
1. You can't append to a stream created by ObjectOutputStream. 2. When you get an exception, print the stack trace. Not some message of your own devising. In this case e.printStackTrace(); is sufficient. 3. while ((o = ois.readObject()) != null ) isn't a valid loop. readObject() doesn't return null at end of stream: it throws EOFException. null can occur any time in the stream you wrote one.Warwick
@Gruzz A StackTrace is basically just an error message. Also, can you let me know if my answer helps you? I have a hunch it will, but you never know.Saharan
@Gruzz Until you provide the stack trace this question is incomplete and unanswerable.Warwick
@EJP Here's where the stack trace is at now: java.io.StreamCorruptedException: invalid stream header: 0AACED00 SC Exception at ... Process finished with exit code 0 It's too long for this comment area.Felske
Stack traces should be posted in the question. The reason for the invalid stream header is mentioned in my point (1) above.Warwick
@EJP If I can't append using ObjectOutputStream then what is the point of having an ObjectOutputStream?Felske
W
4
 java.io.StreamCorruptedException: invalid stream header: 0AACED00 

This is caused by appending to the FileOutputStream. As I mentioned in a comment above, you can't append to a stream written by ObjectOutputStream, at least not without special measures. Keep the file and the ObjectOutputStream open until you've written all the objects you want to write, then close it, then deserialize from it.

NB As I also mentioned,

while ((object = in.readObect()) != null)

is not a valid object-reading loop. readObject() doesn't return null at end of stream: it throws EOFException. null can occur anywhere in the stream, any time you write one. The correct form of the loop is:

try
{
    for (;;)
    {
        Object object = in.readObject();
        // ...
    }
}
catch (EOFException exc)
{
    // end of stream
}
// other catch blocks ...

NB 2 This:

oos.writeObject(object + "\n");

should be just

oos.writeObject(object);

Otherwise you're implicity calling toString() and pointlessly appending a line terminator, so the result of readObject() will be a String, not the original object.

Warwick answered 10/11, 2015 at 1:5 Comment(1)
Thank you @EJP. That answer clears up a lot of what I wasn't understanding!Felske
S
0

I think this was caused by the lack of a serialVersionUID.

Whenever you serialize an object, the ClassLoader needs something to verify the new loaded object against to verify it and ensure its compatibility. In order to do this, you just need to define a field in your class like this:

private static final long serialVersionUID = 12358903454875L;

Your IDE may have also given you a warning stating the lack of it (Eclipse does this).

This should solve your problem.

You can learn more in this excellent answer by Jon Skeet here: What is a serialVersionUID and why should I use it?.

Saharan answered 10/11, 2015 at 0:14 Comment(6)
It would be caused by the lack of a serialVersionUID if he had versioned the class. Not otherwise.Warwick
@EJP Are you sure? This article seems to support my theory, at least looking briefly at the OPs code, in that it looks like he's trying to deserialize an object. Of course, I don't know much about serialization (and I don't normally use it), but this may be the case.Saharan
Inserting that line of code into my 'Tree' class let it read one Object from the file, but now it throws a StreamCorruptedException. This may have to do with some of the things @EJP was saying.Felske
@Gruzz Alright, that helps. In that case, I would now expect the comment from EJP above on your question to now provide you with a solution :)Saharan
Arbitrary Internet junk such as your link doesn't have any status in this discussion. My reference is the Object Serialization Specification, where it says "Each versioned class must identify the original class version for which it is capable of writing streams and from which it can read ... The value must be declared in all versions of a class except the first" [emphasis added]. But there is nothing in your link that supports your assertion. serialVersionUID isn't even mentioned.Warwick
In any case a serialVersionUID problem would show up as an InvalidClassException, not a StreamCorruptedException. Answer is completely incorrect.Warwick

© 2022 - 2024 — McMap. All rights reserved.