In my application I was trying to save a BufferedImage
to a PNG file using ImageIO
. The file is chosen by the user so I need to react to errors that might happend (e.g. user tries to save in a location he has no write permission for). However I am unable to catch the IOException
that occurs.
The following code shows the problem. Trying to save to "/foo" should throw an exception for most users on *nix systems, since they do not have write permission in the root directory.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class IOTest {
public static void main(String[] args) {
BufferedImage img = new BufferedImage(640, 480,
BufferedImage.TYPE_INT_RGB);
try {
File f = new File("/foo");
ImageIO.write(img, "png", f);
} catch (IOException e) {
System.out.println("Caught IOException!");
}
}
}
However, the exception is not caught. Output:
java.io.FileNotFoundException: /foo (Permission denied)
at java.io.RandomAccessFile.open(Native Method)
at java.io.RandomAccessFile.<init>(RandomAccessFile.java:233)
at javax.imageio.stream.FileImageOutputStream.<init>(FileImageOutputStream.java:69)
at com.sun.imageio.spi.FileImageOutputStreamSpi.createOutputStreamInstance(FileImageOutputStreamSpi.java:55)
at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:419)
at javax.imageio.ImageIO.write(ImageIO.java:1530)
at IOTest.main(IOTest.java:16)
Exception in thread "main" java.lang.NullPointerException
at javax.imageio.ImageIO.write(ImageIO.java:1538)
at IOTest.main(IOTest.java:16)
Note that FileNotFoundException
is a subclass of IOException
so it should get caught. A second catch block did not help either:
catch (FileNotFoundException e) {
System.out.println("Caught FileNotFoundException!");
} catch (IOException e) {
System.out.println("Caught IOException!");
}
What am I doing wrong?
It stems from the details of ImageIO
implementation. You will circumvent the problem if you don't pass the File
instance to ImageIO.write
, but first try to open a FileOutputStream
yourself and pass that to write
.
This is a more precise analysis of what happens in ImageIO.write
. Line 1530:
stream = createImageOutputStream(output);
Line 1538:
stream.close();
And if you take a look at the implementation of createImageOutputStream
, you'll see several code paths that return null
.
It looks like the ImageIO.write
method prints the IOException
but really doesn't handle it and ends with a NullPointerException
. In this specific case of a buggy library, maybe you should catch any RuntimeException
...
Of course it will be better to test before if the directory exists and is writable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With