java.net.URL чтение потока в байт [] - PullRequest
41 голосов
/ 19 февраля 2010

Я пытаюсь прочитать изображение из 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();

Мой второй подход был таким (как вы увидите, длина содержимого извлекается другим способом):

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

Оба кода приводят к повреждению изображения ... Я уже читал этот пост из stackoverflow

Ответы [ 6 ]

58 голосов
/ 19 февраля 2010

Нет никакой гарантии, что предоставленная вами длина контента действительно правильная. Попробуйте что-то похожее на следующее:

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().

Этот код не тестировался (я только что написал его в поле для ответов), но это достаточно близкое приближение к тому, что, я думаю, вы ищете.

27 голосов
/ 19 февраля 2010

Просто расшифровываю ответ Барнарда с помощью com-io. Отдельный ответ, потому что я не могу отформатировать код в комментариях.

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)

20 голосов
/ 08 января 2013

Вот чистое решение:

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();
}
11 голосов
/ 09 марта 2011
byte[] b = IOUtils.toByteArray((new URL( )).openStream()); //idiom

Обратите внимание, что в приведенном выше примере поток не закрыт.

, если вы хотите (76-символьный) блок (с использованием кодека commons) ...

byte[] b = Base64.encodeBase64(IOUtils.toByteArray((new URL( )).openStream()), true);
10 голосов
/ 15 мая 2015

Я очень удивлен, что никто здесь не упомянул проблему подключения и тайм-аут чтения . Может случиться (особенно на 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
    }
}
1 голос
/ 19 февраля 2010

Длина содержимого - это просто заголовок HTTP. Вы не можете доверять этому. Просто прочитайте все, что вы можете из потока.

Доступно, безусловно, неправильно. Это просто количество байтов, которые можно прочитать без блокировки.

Другая проблема связана с обработкой ресурсов. Закрытие потока должно произойти в любом случае. try / catch / finally сделает это.

...