Hello. I've seen this topic many times before here, and I still have not found a solid answer to the problem:
When you have a file that you've written many serialized objects to, and then you read in the objects, how do you know when you've read in all of the objects?
(Say you don't know exactly how many objects there are.)
readObject does not return null or -1 or something if there are no more objects to read. That's the first suggestion people usually come up with, and it's wrong.
readObject does not throw an EOFException when there are no more objects to read. It throws (from the API of Java 2 SE 5): ClassNotFoundException InvalidClassException StreamCorruptedException OptionalDataException IOException But not EOFException. That's the second suggestion I've seen, but according to the API, it too is wrong.
So, if I've got a file with a bunch of serialized objects in it, and I call readObject repeatedly to read in the objects, how do I know when I've reached the end of the file?
Originally posted by Kentaro Shinbashi: I should also say that EOFException seems to work, but it's undocumented,
It is not undocumented. EOFException is a subclass of IOException and readObject() (among others) throws IOException. If you read the JavaDoc for ObjectInputStream, it states several times that ". . . primitive reads will throw EOFExceptions. . .". I don't like to use exceptions to signal expected events like EOF. Edwin suggested a good work-around. I recommend storing objects to a collection and serializing that.
By "undocumented", I mean that the function readObject() is not specified to throw an EOFException at the end of file. Indeed, the docs say that it throws an IOException on a usual IO related problem; so do you mean that EOF is considered a usual exception?
It is not undocumented. ... If you read the JavaDoc for ObjectInputStream, it states several times that ". . . primitive reads will throw EOFExceptions. . .".
This really isn't very helpful for me, Joe; just because a bunch of other functions that are not apropos to my problem at hand have a certain specified behavior does not mean that I can just infer that other functions will do the same.
Besides, the very fact that the docs take pains to specify this behavior for the primitive read functions and then omit mention of it for the readObject() is sort of suggestive that maybe the readObject() function does something different.
So, when I say "undocumented", I mean actually, that it is not in the documentation, at last not the documentation that I have (Java 5 API).
The readObject method is responsible for reading and restoring the state of the object for its particular class using data written to the stream by the corresponding writeObject method. The method does not need to concern itself with the state belonging to its superclasses or subclasses. State is restored by reading data from the ObjectInputStream for the individual fields and making assignments to the appropriate fields of the object. Reading primitive data types is supported by DataInput.
Any attempt to read object data which exceeds the boundaries of the custom data written by the corresponding writeObject method will cause an OptionalDataException to be thrown with an eof field value of true. Non-object reads which exceed the end of the allotted data will reflect the end of data in the same way that they would indicate the end of the stream: bytewise reads will return -1 as the byte read or number of bytes read, and primitive reads will throw EOFExceptions.
java.io.ObjectInputStream I see that as clearly documenting that under certain circumstances, readObject will throw EOFException. Now, your complaint may be that the documentation for readObject itself does not state that it throws EOFException:
That's because EOFException is a subclass of IOException, so it is not necessary to declare it in the throws clause. This is not unusual. Have a look at the methods of java.io.DataInput, all of which throw EOFException, but are not explicity declared to:
As a matter of fact, the ObjectInputStream documentation above mentions using DataInput to read primitives, so an EOFException would originate in something that implements this interface rather than ObjectInputStream. This may be why the method readObject does not mention this exception, though the class documentation does.
Joined: Jun 08, 2006
Hi, Joe. Thanks for replying.
No, my complaint is not so much that the readObject() method does not declare that it throws an EOFException, but rather that the documentation does not tell us that the readObject() method actually will throw an EOFException upon reaching the end of the file.
Of course the declaration makes sense; polymorphism allows subclasses to be thrown via the declaration of superclasses, and this is nicer than declaring all the possible subclasses that could happen. I understand that.
The problem is that the documentation does not tell us as developers/users what will happen under a really common situation, reaching the end of a file. It really should, because it's a really bad habit to infer behavior from other functions that might have somewhat parallel functionality. Don't you agree?
So, I am aware of the documentation for other methods, like those that read primatives, and I know what they do, because the API helpfully tells me. However, the API for some reason neglects to say it about readObject(), which by the name, one might guess is the centrally important function to a class named "ObjectInputStream".
As for the interface documentation for the DataInput interface, yes, that actually is very helpful. Thank you for pointing that out. I read the documentation for the superclasses, but I neglected to read the documentation for the interfaces.
However, since an Interface declaration cannot determine the actual behavior of the ultimate implementation, the following assertion is still not going to tell me that I should believe that readObject() will throw EOFExceptions:
It is generally true of all the reading methods in this interface that if end of file is reached before the desired number of bytes has been read, an EOFException (which is a kind of IOException) is thrown.
"generally" could mean that all of the read methods except readObject throw the EOFException at EOF. I just don't know.
But I'm not trying to be nitpicky with you, Joe. I'm really just wanting to emphasize that, even looking to the interface documentation, the behavior of readObject() is not really clear. My real complaint is that I wish the API just said that, instead of me having to research it all over the class and interface hierarchy.
So, if anyone from Sun is reading, I'm just requesting that in Java 6 API, if you tell us that readBoolean, readInt, readByte, etc. all throw EOFException at EOF, and readObject does the same thing, why not say so there too?