开发者

javax.imageio.ImageIO Problem creating ImageInputStream

开发者 https://www.devze.com 2023-03-26 03:28 出处:网络
I have a Servlet in Tomcat 5.5 that reads local images sitting on a folder.The image is then sent back to an Applet.

I have a Servlet in Tomcat 5.5 that reads local images sitting on a folder. The image is then sent back to an Applet.

I'm getting this "javax.imageio.IIOException: Can't create an ImageInputStream!" error and not sure whats causing it.

Has anyone had this problem before? Could this be a Thread issue in the ImageIO? I can't reproduce this issue since it occurs about 3 times for every 1000 requests.

EDIT: This is the Servlet code that reads the image. I just use the ImageIO.read(File) in its static form inside the Servlet's doPost method the same way below:

    doPost(req,resp){
       ...
        BufferedImage image = ImageIO.read(imageFile);
       ...
    }

Here is the source code for javax.imageio.ImageIO.read(File):

    public static BufferedImage read(File input) throws IOException {
    if (input == null) {
        throw new IllegalArgumentException("input == null!");
    }
    if (!input.canRead()) {
        throw new IIOException("Can't read input file!");
    }

    ImageInputStream stream = createImageInputStream(input);
    if (stream == null) {
   开发者_开发技巧     throw new IIOException("Can't create an ImageInputStream!");
    }
    BufferedImage bi = read(stream);
    if (bi == null) {
        stream.close();
    }
    return bi;
    }


If the sole functional requirement is to read images from local disk and return it unmodified to the HTTP response using a servlet, then you do not need the ImageIO at all. It only adds unnecessary overhead and other problems like you're having now.

Get rid of the ImageIO stuff and just stream the raw image straight from disk to HTTP response, along a set of proper response headers. For example,

String name = request.getParameter("name");
File file = new File("/path/to/images", name);

response.setContentType(getServletContext().getMimeType(file.getName()));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");

InputStream input = null;
OutputStream output = null;

try {
    input = new BufferedInputStream(new FileInputStream(file));
    output = new BufferedOutputStream(response.getOutputStream());
    byte[] buffer = new byte[8192];

    for (int length; (length = input.read(buffer)) > 0;) {
        output.write(buffer, 0, length);
    }
} finally {
    if (output != null) try { output.close(); } catch (IOException logOrIgnore) {}
    if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
}

That's all. You only need ImageIO whenever you would like to manipulate the image in server's memory before returning it, e.g. resizing, transforming or something.

Another, more robust, example of such a servlet can be found here and a more advanced one here.


The source I have (Java5 but I doubt it has changed a lot) states that if there are no ImageInputStream service providers registered, the createImageInputStream method returns null and thus you get that exception.

From the JavaDoc on IIORegistry.getDefaultInstance() which is used by ImageIO:

Each ThreadGroup will receive its own instance; this allows different Applets in the same browser (for example) to each have their own registry.

Thus it might actually be a threading problem in that you get a plain new instance of IIORegistry.

Edit: digging deeper into the source I found the following:

Most likely you'd get a FileImageInputStream, since you pass in a file. However, if an exception occurs the service provider returns null. Thus there might be a FileNotFoundException or any other IOException being thrown which causes the stream not to be created.

Unfortunately, there's no logging in the code, thus you'd have to debug somehow. It's probably due to missing file permissions, a corrupted/incomplete file or the file missing.

Here's the Java5 source for FileImageInputStreamSpi#createInputStreamInstance()

public ImageInputStream createInputStreamInstance(Object input,
                                                  boolean useCache,
                                                  File cacheDir) {
    if (input instanceof File) {
        try {
            return new FileImageInputStream((File)input);
        } catch (Exception e) {
            return null;
        }
    } else {
        throw new IllegalArgumentException();
    }
}


Where is your use of close() methods within the exception handling? Streams have to be closed when there are exceptions, too, as well as normal termination of the block of the code.

The symptom sounds like you run out of heap space or sometime.

It is not the coding errors that others pointed out, since the problem is intermittent.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号