java.net.URL 读取流到 byte[]

问题描述 投票:0回答:9

我正在尝试从 URL 读取图像(使用 Java 包 java.net.URL) 到 byte[]。 “一切”工作正常,除了内容没有完全从流中读取(图像已损坏,它不包含所有图像数据)...字节数组被保存在数据库中(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();

这两个代码都会导致图像损坏...... 我已经读过这篇文章来自 Stack Overflow

java arrays image url
9个回答
68
投票

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

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()
从中获取字节数组。

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


35
投票

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

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)


27
投票

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

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();
}

16
投票

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

以下代码(也使用 Apache IO Commons)考虑到了这一点,并等待 max. 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
    }
}

15
投票

使用 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>

12
投票
byte[] b = IOUtils.toByteArray((new URL( )).openStream()); //idiom

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

如果您想要一个(76 个字符)块(使用通用编解码器)...

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

1
投票

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

可用肯定是错误的。这只是在不阻塞的情况下可以读取的字节数。

另一个问题是你的资源处理。无论如何,关闭流都必须发生。 try/catch/finally 会做到这一点。


1
投票

指定超时很重要,尤其是当服务器需要响应时。使用纯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();
}

0
投票

使用依赖项,例如 hutool-bom:

import java.io.InputStream;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.URLUtil;

public final class PdfUtil {

    private static byte[] readBytes(String urlStr) {
        URL url = URLUtil.toUrlForHttp(urlStr);
        InputStream inputStream = URLUtil.getStream(url);
        return IoUtil.readBytes(inputStream, true);
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.