1

我正在尝试从 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());
4

3 回答 3

1
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。

于 2021-05-10T21:39:02.373 回答
0

作为@rmunge 提出的解决方案的替代方案,Apache Commons IO 库提供了IOUtils在您的用例中非常有用的类。

例如,如果您使用 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);

对于您的评论,如果您试图避免网络延迟问题的问题,如果对 a 的要求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);
  //...
}

当然,您始终可以使用标准 JavaInputStreamOutputStream机制“手动”执行读取和写入:

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 连接进行更多控制,您可以使用URLConnectionorHttpURLConnection或许多 HTTP 客户端库(如Apache HttpClientOkHttp)来命名其中的一些。

以@LuisCarlos 在他的评论中指出的问题为例,以避免可能的泄漏连接:

URLConnection urlConn = null;
try {
  urlConn = url.openConnection();
  urlConn.setConnectTimeout(5000);
  urlConn.setReadTimeout(30000);
  InputStream inputStream = urlConn.getInputStream();
  // the rest of the code...

} catch (Exception e) {
  
}

如果您需要检测实际图像类型,请考虑使用TikaJMimeMagic

于 2021-05-10T22:36:37.200 回答
-2

这是我发现可行的解决方案。感谢上面的两种方法。我宁愿避免使用外部库,但因为环境真的很痛苦。类似地,我应该可以访问 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());
于 2021-05-11T15:25:01.693 回答