javax.imageio.ImageIO Проблема с созданием ImageInputStream

У меня есть сервлет в Tomcat 5.5, который читает локальные изображения, находящиеся в папке. Затем изображение отправляется обратно в апплет.

Я получаю это "javax.imageio.IIOException: не удается создать ImageInputStream!" ошибка и не уверен, что ее вызывает.

У кого-нибудь была эта проблема раньше? Может ли это быть проблемой с потоком в ImageIO? Я не могу воспроизвести эту проблему, так как она возникает примерно 3 раза на каждые 1000 запросов.

РЕДАКТИРОВАТЬ: это код сервлета, который читает изображение. Я просто использую ImageIO.read(File) в его статической форме внутри метода doPost сервлета так же, как показано ниже:

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

Вот исходный код для 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;
    }

person Marquinio    schedule 03.08.2011    source источник
comment
Где код для созданияImageInputStream? Это статический метод в ImageInputStream, статически импортированный или что-то еще?   -  person Jon Skeet    schedule 03.08.2011
comment
Я вызываю ImageIO.read(File) из сервлета doPost().   -  person Marquinio    schedule 03.08.2011
comment
Нет, я имею в виду, что вы делаете вызов createImageInputStream, но неясно, является ли это статически импортированным вызовом ImageInputStream.createImageInputStream или чем-то еще.   -  person Jon Skeet    schedule 03.08.2011
comment
@ Джон, скорее всего, ImageIO.createImageInputStream(...).   -  person Thomas    schedule 03.08.2011
comment
О, createImageInputStream — это статический метод. На самом деле это часть библиотеки ImageIO. ImageIO — это библиотека Java, которую я просто использую.   -  person Marquinio    schedule 03.08.2011


Ответы (3)


В источнике, который у меня есть (Java5, но я сомневаюсь, что он сильно изменился), говорится, что если нет зарегистрированных поставщиков услуг ImageInputStream, метод createImageInputStream возвращает значение null, и поэтому вы получаете это исключение.

Из JavaDoc на IIORegistry.getDefaultInstance(), который используется ImageIO:

Каждая ThreadGroup получит свой собственный экземпляр; это позволяет различным апплетам в одном и том же браузере (например) иметь свой собственный реестр.

Таким образом, на самом деле это может быть проблема с потоками, поскольку вы получаете простой новый экземпляр IIORegistry.

Редактировать: копаясь глубже в источнике, я нашел следующее:

Скорее всего, вы получите FileImageInputStream, так как вы передаете файл. Однако, если возникает исключение, поставщик услуг возвращает null. Таким образом, может быть выброшен FileNotFoundException или любой другой IOException, из-за которого поток не будет создан.

К сожалению, в коде нет регистрации, поэтому вам придется как-то отлаживать. Вероятно, это связано с отсутствием прав доступа к файлам, поврежденным/неполным файлом или отсутствием файла.

Вот источник Java5 для 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();
    }
}
person Thomas    schedule 03.08.2011
comment
Я предполагаю, что не должно быть проблемы с потоком при выполнении ImageIO.read(File) внутри сервлета, верно? Может ли это быть состоянием гонки в Image.read(File) в случаях, когда сервлет получает два или более одновременных запроса? Если нет, то я, вероятно, должен начать изучать ваше предложение. - person Marquinio; 03.08.2011

Если единственным функциональным требованием является чтение изображений с локального диска и возврат их неизмененными в ответ HTTP с помощью сервлета, то вам не вообще не нужен ImageIO. Это только добавляет ненужные накладные расходы и другие проблемы, как у вас сейчас.

Избавьтесь от ImageIO материала и просто передавайте необработанное изображение прямо с диска в ответ HTTP вместе с набором правильных заголовков ответа. Например,

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) {}
}

Это все. Вам нужно только ImageIO всякий раз, когда вы хотите манипулировать изображением в памяти сервера перед его возвратом, например. изменение размера, преобразование или что-то в этом роде.

Другой, более надежный пример такого сервлета можно найти здесь. расширенный здесь.

person BalusC    schedule 03.08.2011
comment
Да, ты прав. Я буду помнить об этом, если у меня будет возможность изменить свой код. - person Marquinio; 03.08.2011

Где вы используете методы close() в обработке исключений? Потоки приходится закрывать и при возникновении исключений, как и при нормальном завершении блока кода.

Симптом звучит так, будто у вас закончилось место в куче или когда-то.

Это не ошибки кодирования, на которые указывали другие, поскольку проблема носит периодический характер.

person Yoichi    schedule 10.12.2013