将 URL 中的二进制图像数据读入 HttpUrlConnect::URL 中的 ByteArrayInputStream

Read the binary image data from a URL into a ByteArrayInputStream from 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());
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,请参阅 here 的替代方法。这个解决方案的主要缺点是它必须先将整个文件读入内存。如果您无论如何都计划将二进制数据转发到其他进程,您可以省略 ByteArray 流并将内容直接传输到 OutputStream。

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

例如,如果您使用的是 Maven,则可以在 pom.xml 中导入包括以下 dependency 的库:​​

<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 InputStreamOutputStream 机制“手动”执行读写:

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 连接进行更多控制,您可以使用 URLConnection or HttpURLConnection, or many HTTP client libraries like Apache HttpClient or OkHttp 来命名其中的一些连接。

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

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

这是我发现有效的解决方案。感谢您提供上述两种方法。我宁愿避免外部库,但因为环境真的很痛苦。类似的,我应该可以访问 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());