【问题标题】:java.net.URL read stream to byte[]java.net.URL 读取流到字节 []
【发布时间】:2011-01-18 17:00:35
【问题描述】:

我正在尝试从 URL 读取图像(使用 Java 包 java.net.URL) 到一个字节[]。 “一切”工作正常,除了内容没有完全从流中读取(图像已损坏,它不包含所有图像数据)......字节数组被保存在数据库(BLOB)中.我真的不知道正确的方法是什么,也许你可以给我一个提示。 :)

这是我的第一种方法(代码格式化,删除了不必要的信息......):

URL u = new URL("http://localhost:8080/images/anImage.jpg");
int contentLength = u.openConnection().getContentLength();
Inputstream openStream = u.openStream();
byte[] binaryData = new byte[contentLength];
openStream.read(binaryData);
openStream.close();

我的第二种方法是这个(你会看到contentlength 正在以另一种方式获取):

URL u = new URL(content);
openStream = u.openStream();
int contentLength = openStream.available();
byte[] binaryData = new byte[contentLength];
openStream.read(binaryData);
openStream.close();

这两个代码都导致图像损坏... 我已经阅读了这篇文章from Stack Overflow

【问题讨论】:

    标签: java arrays image url


    【解决方案1】:

    无法保证您提供的内容长度实际上是正确的。尝试类似以下的方法:

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    InputStream is = null;
    try {
      is = url.openStream ();
      byte[] byteChunk = new byte[4096]; // Or whatever size you want to read in at a time.
      int n;
    
      while ( (n = is.read(byteChunk)) > 0 ) {
        baos.write(byteChunk, 0, n);
      }
    }
    catch (IOException e) {
      System.err.printf ("Failed while reading bytes from %s: %s", url.toExternalForm(), e.getMessage());
      e.printStackTrace ();
      // Perform any other exception handling that's appropriate.
    }
    finally {
      if (is != null) { is.close(); }
    }
    

    然后您将在baos 中获得图像数据,您可以通过调用baos.toByteArray() 从中获取一个字节数组。

    此代码未经测试(我只是将其写在答案框中),但它与我认为您所追求的相当接近。

    【讨论】:

    • 请不要写一个空的catch块,即使是在一个例子中!至少把e.printStackTrace()放在那里!示例有成为生产代码的趋势,我们都必须在以后使用它。
    • 你说得对;感谢您指出了这一点。我在示例中添加了更有意义的异常处理。
    • 使用 commons.apache.org/io/api-1.4/org/apache/commons/io/… 。这将使代码看起来更干净。
    • 感谢您的回答,您的方法确实有效:) 我必须将数据逐位(或定义的块值)写入 ByteArrayOutputStream(最终将使用 .toByteArray() 输出,那是我的错……
    • 在我的应用程序中,此代码在某些情况下会挂在 is.read(byteChunk) 上,并且从不连续。
    【解决方案2】:

    只是用 commons-io 扩展 Barnards 的答案。单独的答案,因为我无法在 cmets 中格式化代码。

    InputStream is = null;
    try {
      is = url.openStream ();
      byte[] imageBytes = IOUtils.toByteArray(is);
    }
    catch (IOException e) {
      System.err.printf ("Failed while reading bytes from %s: %s", url.toExternalForm(), e.getMessage());
      e.printStackTrace ();
      // Perform any other exception handling that's appropriate.
    }
    finally {
      if (is != null) { is.close(); }
    }
    

    http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toByteArray(java.io.InputStream)

    【讨论】:

    【解决方案3】:

    这是一个干净的解决方案:

    private byte[] downloadUrl(URL toDownload) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    
        try {
            byte[] chunk = new byte[4096];
            int bytesRead;
            InputStream stream = toDownload.openStream();
    
            while ((bytesRead = stream.read(chunk)) > 0) {
                outputStream.write(chunk, 0, bytesRead);
            }
    
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    
        return outputStream.toByteArray();
    }
    

    【讨论】:

    • 不要忘记调用'stream'的close方法来释放使用的资源。
    【解决方案4】:

    我很惊讶这里没有人提到连接和读取超时的问题。请求可能会挂起并永远等待(尤其是在 Android 和/或网络连接不佳的情况下)。

    以下代码(也使用 Apache IO Commons)考虑了这一点,并等待最大。 5 秒后失败:

    public static byte[] downloadFile(URL url)
    {
        try {
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.connect(); 
    
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            IOUtils.copy(conn.getInputStream(), baos);
    
            return baos.toByteArray();
        }
        catch (IOException e)
        {
            // Log error and return null, some default or throw a runtime exception
        }
    }
    

    【讨论】:

      【解决方案5】:
      byte[] b = IOUtils.toByteArray((new URL( )).openStream()); //idiom
      

      但是请注意,在上面的示例中,该流并未关闭。

      如果你想要一个(76 个字符)块(使用公共编解码器)...

      byte[] b = Base64.encodeBase64(IOUtils.toByteArray((new URL( )).openStream()), true);
      

      【讨论】:

        【解决方案6】:

        使用 commons-io IOUtils.toByteArray(URL):

        String url = "http://localhost:8080/images/anImage.jpg";
        byte[] fileContent = IOUtils.toByteArray(new URL(url));
        

        Maven 依赖:

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

        【讨论】:

          【解决方案7】:

          内容长度只是一个 HTTP 标头。你不能相信它。只需从流中读取所有内容即可。

          Available 肯定是错误的。就是不阻塞可以读取的字节数。

          另一个问题是您的资源处理。在任何情况下都必须关闭流。 try/catch/finally 会这样做。

          【讨论】:

          • 感谢您的回答。我在我的代码发布中省略了 try/catch。但是我怎么知道流的确切长度呢?我必须分配字节[],所以我必须提供一个长度。分配一个固定长度(比如 1024)并从一个位置读取到一个偏移量,检查流是否包含数据,复制到一个新数组,合并所有字节 [] 不是最好的解决方案......
          【解决方案8】:

          指定超时很重要,尤其是在服务器需要响应时。纯Java,不使用任何依赖:

          public static byte[] copyURLToByteArray(final String urlStr,
                  final int connectionTimeout, final int readTimeout) 
                          throws IOException {
              final URL url = new URL(urlStr);
              final URLConnection connection = url.openConnection();
              connection.setConnectTimeout(connectionTimeout);
              connection.setReadTimeout(readTimeout);
              try (InputStream input = connection.getInputStream();
                      ByteArrayOutputStream output = new ByteArrayOutputStream()) {
                  final byte[] buffer = new byte[8192];
                  for (int count; (count = input.read(buffer)) > 0;) {
                      output.write(buffer, 0, count);
                  }
                  return output.toByteArray();
              }
          }
          

          使用依赖,例如HC Fluent:

          public byte[] copyURLToByteArray(final String urlStr,
                  final int connectionTimeout, final int readTimeout)
                          throws IOException {
              return Request.Get(urlStr)
                      .connectTimeout(connectionTimeout)
                      .socketTimeout(readTimeout)
                      .execute()
                      .returnContent()
                      .asBytes();
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-26
            • 2021-04-03
            • 2011-12-21
            相关资源
            最近更新 更多