Java io ugly try-finally block
Is there a not so ugly way of treat the close()
exception to close both streams then:
InputStream in = new FileInputStream(inputFileName);
OutputStream out = new FileOutputStream(outputFileName);
try {
copy(in, out);
} finally {
try {
in.close();
} catch (Exception e) {
try {
// event if in.close fails, need to close the out
out.close();
} catch (Exception e2) {}
throw e; // and throw the 'in' exception
}
}
out.close();
}
update: All the above code is within one more try-catch, thanks for the warnings.
FINALLY (after the answers):
And a good utility method can be done using Execute Around idiom (thanks Tom Hawtin).
This is the correct idom (and it works fine):
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(inputFileName);
out = new FileOutputStream(outputFileName);
copy(in, out);
finally {
close(in);
close(out);
}
public static void close(Closeable c) {
if (c == null) return;
try {
c.close();
} catch (IOException e) {
//log the exception
}
}
The reason this works fine is that the exception thrown before you got to finally will be thrown after your finally code finishes, provided that your finally code doesn't itself throw an exception or otherwise terminate abnormally.
Edit: As of Java 7 (and Android SDK 19 - KitKat) there is now a Try with resources syntax to make this cleaner. How to deal with that is addressed in this question.
You could implement a utility method:
public final class IOUtil {
private IOUtil() {}
public static void closeQuietly(Closeable... closeables) {
for (Closeable c : closeables) {
if (c != null) try {
c.close();
} catch(Exception ex) {}
}
}
}
Then your code would be reduced to:
try {
copy(in, out);
} finally {
IOUtil.closeQuietly(in, out);
}
Additional
I imagine there'll be a method like this in a 3rd party open-source library. However, my preference is to avoid unnecessary library dependencies unless I'm using a large portion of its functionality. Hence I tend to implement simple utility methods like this myself.
try {
final InputStream in = new FileInputStream(inputFileName);
try {
final OutputStream out = new FileOutputStream(outputFileName);
try {
copy(in, out);
out.flush(); // Doesn't actually do anything in this specific case.
} finally {
out.close();
}
} finally {
in.close();
}
} catch (IOException exc) {
throw new SomeRelevantException(exc);
}
Remember that opening a stream may throw an exception, so you do need a try
between the stream openings (please don't do some hack involving null
s. Anything can throw an Error
(which are not an instances of Exception
).
It turns out that catch
and finally
should rarely share the same try
.
Since Java SE 7 you can write use try-with-resource to avoid so much indentation. It more or less does the same thing although there are suppressed exception hidden away.
try (
final InputStream in = new FileInputStream(inputFileName);
final OutputStream out = new FileOutputStream(outputFileName);
) {
copy(in, out);
out.flush(); // Doesn't actually do anything in this specific case.
} catch (IOException exc) {
throw new SomeRelevantException(exc);
}
You may want to use the Execute Around idiom.
I believe the standard good way to copy is using NIO's transferTo
/transferFrom
.
I strongly believe that in Java 7.0, you do not need to explicitly close the stream yourself anymore. Language Features in Java 7
try (BufferedReader br = new BufferedReader(new FileReader(path)) {
return br.readLine();
}
Guava has very nice IO APIs that eliminate the need for this. For instance, your example would be:
Files.copy(new File(inputFileName), new File(outputFileName));
More generally, it uses the concept of InputSupplier
s and OutputSupplier
s to allow the InputStream
s and OutputStream
s to be created within its utility methods, allowing it full control over them so it can handle closing properly.
Additionally, it has Closeables.closeQuietly(Closeable)
which is basically the type of method most of the answers have suggested.
The IO stuff in it is still in beta and subject to change, but it's worth checking out and even using, depending on what it is you're working on.