【问题标题】:Read the binary image data from a URL into a ByteArrayInputStream from HttpUrlConnect::URL从 HttpUrlConnect::URL 将二进制图像数据从 URL 读取到 ByteArrayInputStream
【发布时间】:2021-05-04 18:55:34
【问题描述】:

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

【问题讨论】:

  • 您真正想要完成的是什么?你有 Image 对象,为什么要把它扔到一个输出流中只重定向到另一个输入流呢?
  • 我正在尝试将二进制数据传递给另一个进程,该进程将对其进行编码以便在 json 消息中传输。
  • 为什么?完全浪费时间和空间。只需将输入流(或者实际上是 URL)传递给其他进程。
  • 为什么,确实如此。这是在低效且不适当的集成解决方案馈送和低效的定制专有系统中运行的定制,该系统需要存储图像以避免延迟。

标签: java url bytearrayinputstream


【解决方案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,请参阅here 以获取替代方法。该解决方案的主要缺点是它必须首先将整个文件读入内存。如果您仍然打算将二进制数据转发到其他进程,则可以省略 ByteArray 流并将内容直接传输到 OutputStream。

【讨论】:

    【解决方案2】:

    作为@rmunge 提出的解决方案的替代方案,Apache Commons IO 库提供了 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);
    

    对于您的 cmets,如果您试图避免网络延迟问题,如果对 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 连接进行更多控制,您可以使用 URLConnectionHttpURLConnection,或许多 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

    【讨论】:

    • 当您已经拥有另一个 InputStream 时,究竟是什么?
    • @user207421 感谢您的反馈,我同意您的看法,但是 OP 在问题中表示他/她有这个要求,也许这个问题只是显示了问题的一部分,并且回答尝试解决它。此外,请考虑查看IOUtils.toBufferedInputStreamjavadoc,例如:如您所见,将一个InputStream 转换为另一个(更有效),在某些情况下可能很有价值。
    • @user207421 如您所见,请尝试提供有关整个问题的更多信息,而不仅限于InputStream 转换本身。它还建议使用更方便的库来与 HTTP 交互,以获取资源并处理必要的实际图像格式。
    • 在某些情况下,如果您让“url.openStream();”,由于某种原因无法读取服务器中的资源(例如图像)您几乎可以永远等待响应。相反,在打开连接之前设置连接超时和读取超时是个好主意URLConnection urlConn = null; try { urlConn = url.openConnection(); urlConn.setConnectTimeout(5000); urlConn.setReadTimeout(30000); } catch (Exception e) { } 然后更改这行代码:InputStream inputStream = urlConn.getInputStream();
    • 非常感谢@LuisCarlos 的评论,非常感谢。我完全同意你的看法:答案只是尝试触及问题的表面,提供多种选择,但绝对有很大的改进空间。谢谢!!
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-14
      • 2011-03-12
      • 2022-11-07
      • 1970-01-01
      • 2021-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多