java.net.URL将流读取到字节[]

java.net.URL将流读取到字节[],java,arrays,image,url,Java,Arrays,Image,Url,我正在尝试从URL(使用Java包)读取图像 java.net.URL)转换为字节[]。“一切”都很好,除了内容不是完全从流中读取(图像已损坏,它不包含所有图像数据)。。。字节数组正在数据库(BLOB)中持久化。我真的不知道正确的方法是什么,也许你可以给我一个提示。:) 这是我的第一种方法(代码格式化,删除不必要的信息…): 我的第二种方法是这一种(您将看到,contentlength以另一种方式获取): 这两个代码都会导致图像损坏。。。 我已经读过这篇文章。内容长度只是一个HTTP头。你不能相

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

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

我的第二种方法是这一种(您将看到,
contentlength
以另一种方式获取):

这两个代码都会导致图像损坏。。。
我已经读过这篇文章。

内容长度只是一个HTTP头。你不能相信它。只要从这条小溪里读你能读到的一切

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


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

不能保证您提供的内容长度实际上是正确的。尝试类似于以下内容的操作:

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()
可以从中获得字节数组


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

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

但是请注意,在上面的示例中,该流没有关闭

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


这里有一个干净的解决方案:

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

我很惊讶这里没有人提到连接和读取超时的问题。请求可能会永远挂起并等待(特别是在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
    }
}

指定超时非常重要,特别是当服务器需要响应时。使用纯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();
    }
}
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
使用依赖项,例如:

使用commons io:

Maven依赖项:

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();
    }
}
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

公地io
公地io
2.6

谢谢您的回答。我在代码发布中省略了try/catch。但是我怎么知道小溪的确切长度呢?我必须分配字节[],所以我必须提供一个长度。分配一个固定长度(比如1024)并从一个位置读取到一个偏移量,检查流是否包含数据,复制到一个新数组,合并所有字节[]可能不是最好的解决方案…请永远不要写一个空的catch块,即使在示例中也不行!至少在那里放置
e.printStackTrace()
!示例有成为生产代码的趋势,我们以后都必须使用它;谢谢你指出这一点。我在示例中添加了更有意义的异常处理。这将使代码看起来更干净。Thx对于您的答案,您的方法确实有效:)我必须将数据逐位(或定义的块值)写入ByteArrayOutputStream(最终将以.toByteArray()输出),这是我的错…在我的应用程序中,此代码挂起
is.read(byteChunk)
在某些情况下,永远不会连续。这是另一个不错的解决方案,但我将使用第一个解决方案(因为我们不会包含太多的外部lib)。此解决方案对我不起作用-服务器返回HTTP响应代码:403表示URL:别忘了调用“stream”上的close方法来释放使用的资源。
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();
    }
}
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();
}
String url = "http://localhost:8080/images/anImage.jpg";
byte[] fileContent = IOUtils.toByteArray(new URL(url));
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>