ImageIO.read закрывает поток входных данных

#java #image #stream

#java #изображение #поток

Вопрос:

Я записываю изображения и другие данные в двоичный файл. Когда я считываю изображение через ImageIO.read (InputStream) из этого файла, он считывает изображение, все в порядке, но метод закрывает данный входной поток, и я не могу продолжить чтение других данных.

  1. Почему так сделано?
  2. Тогда как читать изображение без закрытия потока?

РЕДАКТИРОВАТЬ: это простой код, который записывает изображение и строку после в файл:

 File f = new File("test.bin");
if(f.exists())
f.delete();
f.createNewFile();
DataOutputStream os = new DataOutputStream(new FileOutputStream(f));
BufferedImage img = ImageIO.read(new File("test.jpg"));
ImageIO.write(img, "jpg", os);
os.writeUTF("test string after image");
os.close();
  

И код, который считывает все:

 DataInputStream is = new DataInputStream(new FileInputStream(f));
BufferedImage img = ImageIO.read(is);
String s = is.readUTF(); // on this line EOFException occurs
System.out.println(s);
  

Вывод NetBeans:

 Exception in thread "main" java.io.EOFException
at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:340)
at java.io.DataInputStream.readUTF(DataInputStream.java:589)
at java.io.DataInputStream.readUTF(DataInputStream.java:564)
at mediamanager.Main.test(Main.java:105)
at mediamanager.Main.main(Main.java:44)
  

Может быть, я делаю что-то не так?

Комментарии:

1. Где я был, когда увидел исключение EOFException? Он просто читает все байты до конца, он не закрывает входной поток!

Ответ №1:

Цитата из документации ImageIO.read(InputStream)

Этот метод не закрывает предоставленный входной поток после завершения операции чтения; при желании вызывающий объект обязан закрыть поток.

Акцент не мой.

Проблема в другом. Возможно, в вашем коде.

Комментарии:

1. Да, я прочитал это. Но в моем коде чтение следующих байтов возвращает -1 и дальнейшее исключение EOFException. Я пытаюсь сделать простой код и опубликовать здесь, если я воспроизведу эту ошибку.

2. Очень странно. Я провел небольшой эксперимент, и кажется, что метод ImageIO.read() считывает больше байтов, чем строго необходимо для чтения изображения. Например, если я запишу 10 000 байт после изображения, я смогу прочитать только 7998 байт после чтения изображения. Я понятия не имею, как это исправить, кроме как зная размер (N) каждого изображения, прочитав N байтов в массиве байтов и прочитав изображение из этого массива байтов.

3. И также кажется, что у вас могла быть обратная ошибка: bugs.java.com/view_bug.do?bug_id=6687964

4. Итак, это ошибка… Что ж, остается записать длину изображения и прочитать его в отдельный поток. Спасибо за вашу помощь!

Ответ №2:

Я вижу две возможные причины такого поведения:

  1. Программа чтения изображений использует буфер для чтения данных из потока для повышения производительности. Таким образом, он считывает больше данных из потока.
  2. Также программа чтения изображений может попытаться прочитать EXIF для уже проанализированного изображения. Такая информация обычно добавляется в конце файла, чтобы избежать полной перезаписи файла, когда вы просто добавляете пару фрагментов информации об изображении.

Попробуйте ImageIO.setUseCash(false) , это может помочь.

Комментарии:

1. Я предлагаю лучшее решение для этого хранилища.

2. Прежде всего, вы должны определить размер данных изображения перед его записью. [Размер] [Изображение] [Текст]. Чтобы прочитать точное количество байтов из потока, вы должны использовать свое собственное расширение InputStream (я не нашел ни одного применимого в java.io ). Что-то вроде следующего: ` private int sizeLeft; @Override int read() { if (sizeLeft < 0) return -1; int readed = origin.read(); if (readed != -1) sizeLeft—; return прочитано; } ` и так далее. Сделайте то же самое для доступных и rest ‘read’ методов.

3. Я попытался записать больше данных после записи строки и вывода позиции во входном потоке. Да, reader считывает поток до конца, но я изменил формат на PNG, который не имеет EXIF.