Считайте данные двоичного изображения из URL-адреса в ByteArrayInputStream из HttpUrlConnect :: URL

Я пытаюсь вытащить изображение из URL-адреса и прочитать его прямо в ByteArrayInputStream. Я нашел один способ сделать это, но для этого требуется тип изображения, и будут разные типы изображений, поэтому я хотел бы найти простой способ просто читать двоичные данные прямо в нем.

Вот моя последняя попытка. Я использую BufferedImage, который не считаю необходимым.

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");

//Read in the image
BufferedImage image = ImageIO.read(url);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
is = new ByteArrayInputStream(baos.toByteArray());

person BenW    schedule 04.05.2021    source источник
comment
Чего вы на самом деле пытаетесь достичь? У вас есть объект Image, так зачем бросать его в выходной поток только для перенаправления на другой входной поток?   -  person Ryan    schedule 04.05.2021
comment
Я пытаюсь передать двоичные данные другому процессу, который закодирует их для передачи в сообщении json.   -  person BenW    schedule 04.05.2021
comment
Почему? Полная трата времени и места. Просто передайте входной поток или URL-адрес другому процессу.   -  person user207421    schedule 11.05.2021
comment
В самом деле, почему. Это настройка, выполняемая внутри неэффективного и неподходящего интеграционного решения, обеспечивающего подачу и неэффективной специализированной проприетарной системы, которая должна хранить изображение из-за страха задержки.   -  person BenW    schedule 11.05.2021


Ответы (3)


URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");

ByteArrayOutputStream baos = new ByteArrayOutputStream();
url.openStream().transferTo(baos);

ByteArrayInputStream in = new ByteArrayInputStream(baos.toByteArray());

Метод transferTo() существует с Java 9. Если вам следует использовать старую версию Java, см. здесь в поисках альтернативы. Главный недостаток этого решения заключается в том, что он должен сначала прочитать весь файл в памяти. Если вы в любом случае планируете пересылать двоичные данные другому процессу, вы можете опустить потоки ByteArray и передать содержимое непосредственно в OutputStream.

person rmunge    schedule 10.05.2021

В качестве альтернативы решению, предложенному @rmunge, библиотека ввода-вывода Apache Commons предоставляет класс _ 1_, что может быть очень полезно в вашем случае использования.

Если вы, например, используете Maven, вы можете импортировать библиотеку, включая следующую зависимость в вашем pom.xml:

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.8.0</version>
</dependency>

Затем вы можете использовать IOUtils следующим образом:

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");
try (
  InputStream imageInputStream = url.openStream();
  ByteArrayOutputStream bOut = new ByteArrayOutputStream()
) {
  // You can obtain a byte[] as well if required
  // Please, consider write to the actual final OutputStream instead
  // of into the intermediate byte array output stream to optimize memory
  // consumption
  IOUtils.copy(imageInputStream, bOut);

  // Create an input stream from the read bytes
  ByteArrayInputStream in = new ByteArrayInputStream(bOut.toByteArray());
  // ...
} catch (IOException ioe) {
  ioe.printStackTrace();
}

Или просто такой подход:

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");
byte[] imageBytes = IOUtils.toByteArray(url);
ByteArrayInputStream in = new ByteArrayInputStream(imageBytes);

Для ваших комментариев, если проблема заключается в том, что вы пытаетесь избежать проблем с задержкой в ​​сети, если требование для ByteArrayInputStream не является строго необходимым, как вы можете видеть в javadocs, возможно, следующий код может быть также полезно:

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");
try (InputStream imageInputStream = url.openStream()) {
  InputStream in = IOUtils.toBufferedInputStream(imageInputStream);
  //...
}

Конечно, вы всегда можете выполнить чтение и запись вручную, используя стандартные механизмы Java InputStream и OutputStream:

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");
try (
  InputStream inputStream = url.openStream();
  BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
  ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
  BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); 
) {
  byte[] buffer = new byte[8192];
  int bytesRead;
  while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
    bufferedOutputStream.write(buffer, 0, bytesRead);
  }

  bufferedOutputStream.flush();

  // Create an input stream from the read bytes
  ByteArrayInputStream in = new ByteArrayInputStream(outputStream.toByteArray());
  // ...
} catch (IOException ioe) {
  ioe.printStackTrace();
}

Если вам требуется больше контроля над базовым URL-соединением, вы можете использовать _ 12_ или HttpURLConnection или многие клиентские библиотеки HTTP, такие как Apache HttpClient или OkHttp, чтобы назвать некоторые из них.

Если вам нужно определить фактический тип изображения, рассмотрите возможность использования Tika или JMimeMagic.

person jccampanero    schedule 10.05.2021
comment
Что именно означает создание еще одного InputStream, когда он у вас уже есть? - person user207421; 11.05.2021
comment
@ user207421 Спасибо за отзыв, и я согласен с вами, но OP указал в вопросе, что у него / нее есть это требование, и, возможно, вопрос показывает только часть проблемы, и ответ пытается ее решить. Кроме того, рассмотрите возможность просмотра javadoc IOUtils.toBufferedInputStream, например: как вы можете видеть, преобразование одного InputStream в другое (более эффективное) может оказаться полезным в некоторых ситуациях. - person jccampanero; 11.05.2021
comment
@ user207421 Пожалуйста, как видите, в ответе постарайтесь дать больше информации обо всей проблеме, не ограничиваясь только InputStream преобразованием. Он также предлагает использовать более удобные библиотеки для взаимодействия с HTTP, чтобы получить ресурс и иметь дело с самим фактическим форматом изображения, если это необходимо. - person jccampanero; 11.05.2021

Вот решение, которое я нашел работающим. Спасибо за два вышеуказанных подхода. Я бы предпочел избегать внешних библиотек, но потому что окружающая среда - это настоящая боль. Точно так же у меня должен быть доступ к Java 9 и transferTo (), но это не работает.

Этот ответчик также был полезен: Convert InputStream (Image) to ByteArrayInputStream

URL url = new URL("http://hobbylesson.com/wp-content/uploads/2015/04/Simple-Acrylic-Painting-Ideas00005.jpg");
        
InputStream source = url.openStream();
byte[] buf = new byte[8192]; 
int bytesRead = 0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((bytesRead = source.read(buf)) != -1) {
     baos.write(buf, 0, bytesRead);
}
is = new ByteArrayInputStream(baos.toByteArray());
person BenW    schedule 11.05.2021