2010-02-19 11 views
30

Estoy tratando de leer una imagen de una URL (con el paquete java java.net.URL) a un byte []. "Todo" funciona bien, excepto que el contenido no se lee completamente de la transmisión (la imagen está corrupta, no contiene todos los datos de imagen) ... La matriz de bytes se está conservando en una base de datos (BLOB). Realmente no sé lo que el enfoque correcto es, tal vez usted me puede dar un consejo :)java.net.URL leer flujo a byte []

Ésta es mi primera aproximación (código de formato, informaciones innecesarias eliminadas ...):

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

Mi segundo enfoque era ésta (como se verá el ContentLength se fue a buscar otra manera):

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

Tanto el resultado de código en una imagen dañada ... yo ya leí este post from stackoverflow

Respuesta

51

No hay garantía de que la longitud del contenido que le proporcionen sea realmente correcta. Probar algo parecido a lo siguiente:

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

A continuación, tendrá los datos de imagen en baos, desde donde se puede obtener una matriz de bytes llamando baos.toByteArray().

Este código no ha sido probado (lo acabo de escribir en el recuadro de respuestas), pero es una aproximación bastante cercana a lo que creo que está buscando.

+27

Por favor, nunca escriba una captura vacía- bloquear, ni siquiera en un ejemplo! Ponga al menos 'e.printStackTrace()' allí! Los ejemplos tienen una tendencia a convertirse en código de producción y todos tenemos que trabajar con eso más adelante. –

+2

Tienes toda la razón; gracias por señalar eso. Agregué un manejo de excepciones más significativo al ejemplo. – RTBarnard

+0

Use http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toByteArray(java.io.InputStream). Esto hará que el código se vea mucho más limpio. – Adi

1

La longitud del contenido es simplemente un encabezado HTTP. No puedes confiar en eso. Simplemente lee todo lo que puedas de la transmisión.

Disponible definitivamente es incorrecto. Es solo la cantidad de bytes que se pueden leer sin bloquear.

Otro problema es su manejo de recursos. Cerrar el flujo tiene que suceder en cualquier caso. try/catch/finally hará eso.

+0

Thx por su respuesta. Omito el try/catch en mi publicación de código. Pero, ¿cómo puedo saber la longitud exacta de la transmisión? Tengo que asignar el byte [], así que tengo que proporcionar una longitud. Asigne una longitud fija (digamos 1024) y lea desde una posición hasta una compensación, verifique si la secuencia contiene datos, copiando a una nueva matriz, fusionando todos los bytes [] no podría ser la mejor solución ... –

23

Simplemente ampliando la respuesta de Barnards con commons-io. Respuesta separada porque no puedo formatear el código en los comentarios.

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)

+0

Esa es otra buena solución, pero usaré la primera (porque no incluiremos demasiadas libretas externas). –

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

Nota sin embargo, que la corriente no está cerrada en el ejemplo anterior.

si quieres un trozo (76 caracteres) (usando campos comunes códec) ...

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

-1 para el formato incorrecto y un poco de lenguaje obsceno. – asgs

16

Aquí es una solución limpia:

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

No olvides llamar al método de cierre en 'stream'. para liberar los recursos usados. –

7

Me sorprende mucho que aquí nadie ha mencionado el problema de conexión y tiempo de espera de lectura. Podría suceder (especialmente en Android y/o con un poco de conectividad de red) que la solicitud se cuelgue y espere para siempre.

El siguiente código (que también utiliza Apache IO Commons) tiene esto en cuenta y espera un máximo de.5 segundos hasta que falle:

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 
    } 
}