4

I basically have a similar problem as stated here: EOFexception in Java when reading objectinputstream, but I don't find an answer with clean code.

The answer states that the ObjectInputStream#readObject will throw the exception when the reader reachs the End Of File. After looking in the web for a solution, I haven't found a solution. Could be a good and clean solution for this case?

Note: I have tried this (but it looks ugly and is not clean code). I'm looking for a better solution:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
try {
    Object o;
    while ((o = ois.readObject()) != null) {
        if (o instanceof MyClass) {
            MyClass m = (MyClass)o;
            //use the object...
        }
    }
} catch (EOFException eofex) {
    //do nothing
}  catch (IOException ioex) {
    throw ioex;
    //I have another try/catch block outside to control the life of the ObjectInputStream
}
//later in the code...
ois.close();
Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • I don't find anything wrong with this code. My be your file have no objects. – Bhavik Ambani Oct 02 '12 at 03:36
  • 1
    My file has the objects because I can use them after the `MyClass m = (MyClass)o;` line. It still throws the `EOFException` and I don't know how to get rid of it in a clean way. – Luiggi Mendoza Oct 02 '12 at 03:37
  • At the end of the code this exception will be thrown, this is the basic approach of the Java language. You will have to do manage that exception, nothing wrong with that – Bhavik Ambani Oct 02 '12 at 03:39
  • 1
    @BhavikAmbani It is the 'basic approach' of *this API*, and some others, basically all the `readXXX()` methods except `readLine()` which returns `null`, and of course `read()` itself returns -1. Nothing to do with the 'Java language' itself whatsoever, just the APIs. – user207421 Oct 02 '12 at 03:41
  • 2
    @downvoter: leave a comment explaining your downvote – Luiggi Mendoza Oct 02 '12 at 04:06

5 Answers5

13

That's what's supposed to happen. Your code is wrong. Check the Javadoc. readObject() only returns null if you wrote a null. It doesn't say anything about returning a null at EOF. Looping until readObject() returns null will only stop if you ever wrote a null via writeObject(), and if you didn't you will get an EOFException.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 2
    IF that's supposed to happen, then I can ommit the `while ((o = ois.readObject()) != null)` and turn it into a `while(true)` until the code throws an `EOFException`? Is this the only way out for this? If not, then please provide some code to understand. – Luiggi Mendoza Oct 02 '12 at 03:31
  • 3
    @LuiggiMendoza Correct, that's how to do it. Ignore the usual screams from the 'exceptions should't be used for normal flow control' crew, as they are only relying on their own redefinition of 'normal'; in any case the API doesn't give you any choice. – user207421 Oct 02 '12 at 03:37
  • This is very sad to read, but if it's the only way, then I'll go for it. – Luiggi Mendoza Oct 02 '12 at 03:38
  • 1
    I think this is very poor answer and not expected at this level. This exception will be thrown at every level of the file reading using OOS. – Bhavik Ambani Oct 02 '12 at 03:40
  • 3
    @BhavikAmbani What exactly is 'poor' about this answer? If there is something incorrect in what I have stated please say so. And please explain what exactly you mean by 'at every level of the file reading', because it seems completely meaningless to me. If, as seems probable, you are complaining about the API itself rather than the text of my answer, it is incumbent on you to make that clear. – user207421 Oct 02 '12 at 03:43
  • 3
    @BhavikAmbani I don't think it is a poor answer. If this is the way how Java designers though when doing this design, then there's nothing to do about it. It was *sad* for me because I'm not comfortable having a `try/catch` block as normal behavior, but I guess there's a first time for anything in the life :). – Luiggi Mendoza Oct 02 '12 at 03:44
  • @LuiggiMendoza You've just proved my point above. You're redefining 'normal' to suit yourself. EOF isn't 'normal': it happens once per file. The normal behaviour is to get an object. – user207421 Oct 02 '12 at 03:45
  • 1
    When I read files on C, there was this `while(!EOF)` (or similar, I just don't remember the exact syntax) so I though I could find a similitude in Java, but now I know the similitude is with a `try/catch`. Thanks for the help. – Luiggi Mendoza Oct 02 '12 at 03:48
  • @LuiggiMendoza When you read files with C there was no way to get an object back as the return value of a function call that read from a file. If you want that, you have to either use null and thereby exclude it as a value that can be written to the file, or else you have to have an exception so as not to narrow the bandwidth by using part of it as an out-of-band signal. Or invent some other EOF object and exclude *that* as a valid value. – user207421 Oct 02 '12 at 03:55
  • @LuiggiMendoza - I will call attention to *EJP*'s second sentence: "Your code is wrong." The "clean" solution is to know how many objects have been written to the stream. – parsifal Oct 02 '12 at 18:40
  • @parsifal my code was *wrong* in some way. I already fixed based in both EJP and StephenC answers. – Luiggi Mendoza Oct 02 '12 at 18:45
  • @parsifal That's a solution if and only if it is knowable in advance of writing the stream, or can be transmitted separately. Otherwise it isn't a solution at all, 'clean' or otherwise. And if it does apply, you still have to deal with the possibility of files that don't have the advertised number of items in them, and truncated files: i.e. by catching `IOException`, closing the file, and exiting the read loop. There's nothing 'clean' about adding constraints and data to that. – user207421 Oct 02 '12 at 23:41
12

@EJP's answer has nailed it.

However if you are a paid-up member of the "exceptions should't be used for normal flow control" club* then you can avoid having to catch the exception if you can use some other means to determine when to stop; for example

  • You could start the stream with a count sent as an int or an Integer object.
  • You could mark the end the stream by sending a null.
  • You could mark the end the stream by sending a special object that means "this is the end". It does not need to be a MyClass instance.
  • You could send a List<MyClass> ... though that means that you can't "stream" the objects.

Note that this implies that you are able to change the sender-side code ...


* Membership of this club requires either the ability to assimilate circular arguments, or willingness to blindly accept dogma as truth. :-)


Rather than repeat the arguments ad nauseam, here are some links to some of my answers related to the "normal flow control" debate:

If you read through them, you will see that I don't come down firmly on either side of the fence. Rather, my view is that you should understand the trade-offs, and make a decision about whether exceptions are appropriate or not on a case-by-case basis.

Community
  • 1
  • 1
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
4

You could try this:

boolean check=true;
while (check) {
   try{
       System.out.println(ois.readObject());
   } catch(EOFException ex){
       check=false;
   }
}
ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
  • Welcome to stackoverflow. This might answer te question but a little more explanation might help out the fellow programmers how it works. – Nagama Inamdar Jan 22 '15 at 04:46
  • 4
    Or you could get rid of the variable, and the initialization, and the assignment, and use a `while (true)` loop, *inside* the `try` block, and save yourself several lines of code and the space for a fairly pointless and poorly named variable. – user207421 Apr 07 '15 at 11:53
1

I encountered this error because I had forgot to close an ObjectOutputStream in the code that wrote the data. Once I wrote the data again with code that closed the output stream the data was able to be read in fine.

Evan Siroky
  • 9,040
  • 6
  • 54
  • 73
-1

While readObject() doesn't return NULL when it hits the end of a file, if you control the file from it's inception you could always add NULL right before closing your output stream. It will get passed as an object, but you can then test for end of file as such:

Boolean complete = false;
ObjectInputStream in = <...>

while(complete != true) {
    Object test = (Object)in.readObject();
    if(test != null) { someArrayList.add(test); }
        else { complete = true; }
}
Mercutio
  • 1,152
  • 1
  • 14
  • 33