EOFException when reading files with ObjectInputStream [duplicate] - java

This question already has an answer here:
EOFexception in Java when reading objectinputstream
(1 answer)
Closed 2 years ago.
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();

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.

#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:
Cost of compound if/or versus try/catch in Java 6
What is an alternative to exceptions for flow control?
Regex or Exception Handling?
Check if a file exists before calling openFileInput
Which is faster, try catch or if-else in java (WRT performance)
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.

You could try this:
boolean check=true;
while (check) {
try{
System.out.println(ois.readObject());
} catch(EOFException ex){
check=false;
}
}

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.

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; }
}

Related

Are exceptions well handeled in this code? Is it missing a finally block to close the fileobject?

void appendFile() throws IOException{
FileWriter print = new FileWriter(f, true);
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
print.flush();
print.close();
}
boolean fileExist(){
return f.exists();
}
try{
if (f.fileExist())
f.appendFile();
else {
throw new IOException();
}
}
catch(IOException e) {
e.printStackTrace();
}
I'm not sure if the ecxeption is well handeled? The FileWriter is not going to be created if there is a fileNotFoundException, therefore don't need to be closed. However, is it possible that this code throws another kind of IOException after the file was opened?, and in that case do I need a finally block to close the file.
No.
It doesn't safely close the resource
The general rule is, if you call a constructor of an object that represents a closable resource, or a method that returns one which documents that this counts as 'opening the resource', which often but not always includes new being part of the method name (examples: socket.getInputStream(), Files.newInputStream), then you are responsible for closing it.
The problem is, what if an exception occurs? So, you have to use try/finally, except that's a mouthful, so there's a convenient syntax for this.
The appendFile method should use it; it isn't, that makes it bad code. This is correct:
try (FileWriter print = new FileWriter(f, true)) {
String info = GetData.getWord("Write desired info to File");
print.append(" "); //Write Data
print.append(info);
System.out.println("this executes");
}
Not how it is not neccessary to flush before close (close implies flush), and in this case, not neccessary to close() - the try construct does it for you. It also does it for you if you get out of the {} of the try via a return statement, via control flow (break), or via an exception, or just by running to the } and exiting normally. No matter how - the resource is closed. As it should be.
It throws description-less exceptions
else throw new IOException(); is no good; add a description that explains why the exception happened. throw new IOException("File not found") is better, but throw new FileNotFoundException(f.toString()) is even better: The message should convey useful information and nothing more than that (in other words, throw new IOException("Something went wrong") is horrible, don't do that, that message adds no useful information), should not end in punctuation (throw new IOException("File not found!") is bad), and should throw a type that is most appropriate (if the file isn't there, FileNotFoundException, which is a subtype of IOException, is more appropriate, obviously).
It commits the capital offense
You should not ever write a catch block whose contents are just e.printStackTrace();. This is always wrong.
Here's what you do with a checked exception:
First, think of what the exception means and whether the nature of your method inherently implies that this exception can occur (vs. that it is an implementation detail). In this case, you didn't show us what the method containing that try/catch stuff even does. But let's say it is called appendFile, obviously a method that includes the text 'file' does I/O, and therefore, that method should be declared with throws IOException. It's not an implementation detail that a method named appendFile interacts with files. It is its nature.
This is somewhat in the eye of the beholder. Imagine a method named saveGame. That's less clear; perhaps the mechanism to save may involve a database instead, in which case SQLException would be normal. That's an example of a method where 'it interacts with the file system' is an implementation detail.
The problem that the exception signals is logical, but needs to be more abstract.
See the above: A save file system can obviously fail to save, but the exact nature of the error is abstract: If the save file system is DB-based, errors would show up in the form of an SQLException; if a file system, IOException, etcetera. However, the idea that saving may fail, and that the code that tried to save has a reasonable chance that it can somewhat recover from this, is obvious. If it's a game, there's a user interface; you should most absolutely TELL the player that saving failed, instead of shunting some stack trace into sysout which they probably never even look at! Telling the user that something failed is one way of handling things, not always the best, but here it applies).
In such cases, make your own exception type and throw that, using the wrapper constructor:
public class SaveException extends Exception {
public SaveException(Throwable cause) {
super(cause);
}
}
// and to use:
public void save() throws SaveException {
try {
try (OutputStream out = Files.newOutputStream(savePath)) {
game.saveTo(out);
}
} catch (IOException e) {
throw new SaveException(e);
}
}
If neither applies, then perhaps the exception is either essentially not handleable or not expectable or nearly always a bug. For example, writing to an outputstream that you know is a ByteArrayOutputStream (which can't throw), trying to load the UTF-8 charset (which is guaranteed by the JVM spec and therefore cannot possibly throw NoSuchCharsetException) - those are not expectable. Something like Pattern.compile("Some-regexp-here") can fail (not all strings are valid regexps), but as the vast majority of regexes in java are literals written by a programmer, any error in them is therefore neccessarily a bug. Those, too, are properly done as RuntimeExceptions (which are exceptions you don't have to catch or list in your throws line). Not handleables are mostly an application logic level thing. All fair game for runtimeexceptions. Make your own or use something that applies:
public void save(int saveSlot) {
if (saveSlot < 1 || saveSlot > 9) throw new IllegalArgumentException("Choose a saveslot from 1 to 9");
// ... rest of code.
}
This really feels like door number one: Whatever method this is in probably needs to be declared as throws IOException and do no catching or trying at all.
Minor nit: Uses old API
There's new API for file stuff in the java.nio.file package. It's 'better', in that the old API does a bunch of bad things, such as returning failure by way of a boolean flag instead of doing it right (by throwing an exception), and the new API has far more support for various bits and bobs of what file systems do, such as support for file links and creation timestamps.

How to fix unreported IO Exception. Trying to read a specific line from a .txt file [duplicate]

This question already has an answer here:
What does "error: unreported exception <XXX>; must be caught or declared to be thrown" mean and how do I fix it?
(1 answer)
Closed 8 months ago.
While learning Java I stumble upon this error quite often. It goes like this:
Unreported exception java.io.FileNotFound exception; must be caught or declared to be thrown.
java.io.FileNotFound is just an example, I've seen many different ones. In this particular case, code causing the error is:
OutputStream out = new BufferedOutputStream(new FileOutputStream(new File("myfile.pdf")));
Error always disappears and code compiles & runs successfully once I put the statement inside try/catch block. Sometimes it's good enough for me, but sometimes not.
First, examples I'm learning from do not always use try/catch and should work nevertheless, apparently.
Whats more important, sometimes when I put whole code inside try/catch it cannot work at all. E.g. in this particular case I need to out.close(); in finally{ } block; but if the statement above itself is inside the try{ }, finally{} doesnt "see" out and thus cannot close it.
My first idea was to import java.io.FileNotFound; or another relevant exception, but it didnt help.
What you're referring to are checked exceptions, meaning they must be declared or handled. The standard construct for dealing with files in Java looks something like this:
InputStream in = null;
try {
in = new InputStream(...);
// do stuff
} catch (IOException e) {
// do whatever
} finally {
if (in != null) {
try {
in.close();
} catch (Exception e) {
}
}
}
Is it ugly? Sure. Is it verbose? Sure. Java 7 will make it a little better with ARM blocks but until then you're stuck with the above.
You can also let the caller handle exceptions:
public void doStuff() throws IOException {
InputStream in = new InputStream(...);
// do stuff
in.close();
}
although even then the close() should probably be wrapped in a finally block.
But the above function declaration says that this method can throw an IOException. Since that's a checked exception the caller of this function will need to catch it (or declare it so its caller can deal with it and so on).
Java's checked exceptions make programmers address issues like this. (That's a good thing in my opinion, even if sweeping bugs under the carpet is easier.)
You should take some appropriate action if a failure occurs. Typically the handling should be at a different layer from where the exception was thrown.
Resource should be handled correctly, which takes the form:
acquire();
try {
use();
} finally {
release();
}
Never put the acquire() within the try block. Never put anything between the acquire() and try (other than a simple assign). Do not attempt to release multiple resources in a single finally block.
So, we have two different issues. Unfortunately the Java syntax mixes up the two. The correct way to write such code is:
try {
final FileOutputStream rawOut = new FileOutputStream(file);
try {
OutputStream out = new BufferedOutputStream(rawOut);
...
out.flush();
} finally {
rawOut.close();
}
} catch (FileNotFoundException exc) {
...do something not being able to create file...
} catch (IOException exc) {
...handle create file but borked - oops...
}

How to handle exceptions when reading files with buffered reader?

I have made code to read text (json, xml etc.) from a text file, and convert it into a strings which can then be used by other code to convert into plain old java objects or POJOS that are annotated by jackson.
I am not sure if my code handles the exceptions properly. So far, I have used the principles mentioned after my code (READ THIS DOWN VOTERS !!!), to develop the code. Note that I cannot use try with resources because I am stuck with Java 6 (even though my project JRE is 1.8).
package com.testing;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class JunkEx {
public static void main(String[] args) {
String filePath = ".\\src\\test\\resources\\text-files\\orders\\orders-2017.txt";
String contents = fileToString(filePath);
System.out.println(contents);
}
private static String fileToString(String filePath) {
StringBuilder stringBuilder = null;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(filePath));
stringBuilder = new StringBuilder();
String currentLine;
while ((currentLine = br.readLine()) != null) {
stringBuilder.append(currentLine);
stringBuilder.append("\n");
}
}catch (FileNotFoundException ex1) {
ex1.printStackTrace();
}catch (IOException ex2) {
ex2.printStackTrace();
}finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
}
Principles:
1) Catch the most specific exception first, then the one above it in the exception hierarchy. I.e catch FileNotFoundException 1st and IOException later. Refer point 5 here
2) Do NOT return from inside a finally block, because finally is always executed as long as try "completes" fully or abruptly. Refer this SO answer.
3) Cleanup resources like buffered readers in the finally block. Refer point 1 here.
4) Do not make the callers of the "dangerous" method (i.e. which could throw exceptions), have to know/throw each of the exceptions inside it. I.e dangerous method should not "throws FileNotFoundException, IOException...etc". refer this link, specifically the last paragraph
Flaw in the code:
If any of the first two catch blocks are executed, then its likely that the entire file was not read. But, my method will return a string anyway. The string could be null or incomplete.
Questions -
1) I want to throw an exception when the text file is not successfully converted to a string, i.e. one of the three catch blocks is executed. Should I wrap the exception in each catch block inside a generic Exception object and throw that or do something else ?
2) How can I improve/fix the exception handling of this code?
Project structure:
Simple answer: don't catch the exceptions at all. Let the caller catch them. He's the one who needs to know, and knows what to do about them. This method certainly doesn't.
4) Do not make the callers of the "dangerous" method (i.e. which could throw exceptions), have to know/throw each of the exceptions inside it. I.e dangerous method should not "throws FileNotFoundException, IOException...etc". refer this link, specifically the last paragraph.
I don't think much of this 'principle', and in any case it doesn't actually apply here. The only exceptions thrown are IOException and FileNotFoundException, which is derived from it. The caller doesn't have to deal with both if he doesn't wish to. However he may wish to do exactly that, if for example the file being missing constitutes a deployment error.
You have two options:
Don't catch the exceptions and let the caller deal with them
Catch the exceptions and throw your own custom exception, say FileToStringFailedException, that wraps the actual exception. The wrapping part is extremely important, so that when someone up the call chain does a printStackTrace() you get a Caused By section that explains the real failure.
Either option works, and which one you choose depends on the overall design. For something simple I'd just let the exceptions percolate upwards; if I was designing a large complex library with other custom wrapper exceptions I might choose option 2.
Without a lot more context about what you're doing and where this fits into your system, it's not possible to say one option is "better".
Whatever you do, NEVER interfere with the actual exception. Exceptions are for programmers, not users. If you want "friendly" errors for users, do that at the point where the exceptions are displayed to the users, but make sure the original exceptions are logged for the programmers. otherwise you will regret it severely when your "friendly" exception hides crucial information that you need to troubleshoot a problem.

Java. Try to deserialize if file exists. Otherwise just don't

I am using Serialization to get persistent storage for my library managing app (I know it is not the right way, but it's the way my professor wants it).
I am using the following code inside my main();
controlador.getBiblioteca().getGestorMaterial().setListaLibros((Modelo.ColeccionLibros) controlador.getSerializador().abrirArchivo("libros.dat"));
My Serializador class has the abrirArchivo("FileName.dat") function (openFile in English).
That function looks like this:
public Object abrirArchivo(String nombreDelArchivo) {
Object retorno = null;
try {
lectorArchivos = new ObjectInputStream(new FileInputStream(
nombreDelArchivo));
retorno = lectorArchivos.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return retorno;
}
Now I am trying to check if the program gets a FileNotFoundException for any of the files. If it does, it should just not deserialize the file and go for the next one: that would just mean there is no book in my library yet.
The problem is, if the line runs, it seems to set my book list using setListaLibros() to null. And whenever I try to access that list, i get a NullPointerException. The list was already initialized as an empty list though, so I just need to leave it alone as long as the "libros.dat" file is not found.
What is the right way to get that done?
I don't know if I understand the problem well. However, as I can see in your code, when an exception FileNotFoundException happens, "retorno" will keep null. That's the reason why you get setListaLibros(null).
And then your list will became null. If you don't want that behavior, you should initialize "retorno" with an empty list instead of null.
You could add a line before this: controlador.getBiblioteca().getGestorMaterial().setListaLibros((Modelo.ColeccionLibros) controlador.getSerializador().abrirArchivo("libros.dat")); which checks if the file exists. If it does not, then it prompts the user. This way, the user knows something went wrong and can act accordingly.
Alternatively, you can make a change in your setListLibros method wherein, if the argument passed is null, then you do not do any assignment.
Personally, I would go with the first option.
As a side note, please break down your code, something like so: controlador.getBiblioteca().getGestorMaterial().setListaLibros((Modelo.ColeccionLibros) controlador.getSerializador().abrirArchivo("libros.dat")) can get hard to read and debug.
There is an aspect that the other answers are not mentioning: why are there no serialized objects when your library is empty?!
What I mean is: you could distinguish between "program runs the first time" (and obviously no serialized data exists) or "program ran before; and thus it fully configures itself from serialized data.
Meaning: "being empty" can be a valid state of a library, too. So another option would be to not use a "special value" (aka "no file with data") to represent that information ... but (de)serialize an empty list.
You could check if the file exist like:
String fileName;
File f1 = new File(fileName);
if (f1.exists()) {
//Do the work
}

Do i need to handle or ignore the IOException fired by OutputStream close() function?

In the following code the close function for outPutStream throw an IOException exception that I should catch. My question is do I need to handle it? Since I'm working with mobile devices and I want to make sure that I free all resources that I use, or could I safely ignore the exception.
//...
OutputStream output = null;
try {
output = connection.getOutputStream();
output.write(query.getBytes(charset));
} finally {
if (output != null) try {
output.close();
} catch (IOException e) {
// Do i need to do something here ?
}
}
If the close doesn't work, what can you do?
The only thing you can do is just log the exception, and as #mprabhat has suggested you can set the reference to null to speed up GC.
The java documentation doesn't detail on which all different condition close will throw an IOException hence there isn't much that one can do.
At least you can set the reference of OutputStream to null and log the exception.
In worst case, you can give a warning. But generally, such exceptions are thrown when trying to close an already closed session. In this case, you don't need to do anything.
In Effective Java Joshua Bloch mentions this as one of the exceptions you might want to ignore. Generally though, he says, you do want to do more with exceptions than just logging them.

Categories