web-dev-qa-db-fra.com

java.net.URL lire le flux en octets []

J'essaie de lire une image à partir d'une URL (avec le Java Java.net.URL ) pour un octet []. "Tout" fonctionne très bien, sauf que le contenu n'est pas lu en entier dans le flux (l'image est corrompue, elle ne contient pas toutes les données d'image) ... Le tableau d'octets est conservé dans une base de données (BLOB Je ne sais vraiment pas quelle est la bonne approche, peut-être pourriez-vous me donner un conseil :)

Voici ma première approche (formatage du code, suppression des informations inutiles ...):

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

Ma deuxième approche était celle-ci (comme vous le verrez, la longueur du contenu est récupérée d'une autre manière):

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

Les deux codes résultent en une image corrompue ... J'ai déjà lu ce post de stackoverflow

41
tim.kaufner

Il n'y a aucune garantie que la longueur du contenu que vous fournissez est réellement correcte. Essayez quelque chose qui ressemble à ce qui suit:

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

Vous aurez alors les données d'image dans baos, à partir de laquelle vous pouvez obtenir un tableau d'octets en appelant baos.toByteArray().

Ce code n'est pas testé (je viens de l'écrire dans la boîte de réponse), mais c'est une approximation assez proche de ce que je pense que vous recherchez.

58
RTBarnard

Il suffit d'étendre la réponse de Barnards avec commons-io. Réponse séparée car je ne peux pas formater le code dans les commentaires.

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
Adi

Voici une solution propre:

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();
}
20
Ron Reiter
byte[] b = IOUtils.toByteArray((new URL( )).openStream()); //idiom

Notez cependant que ce flux n'est pas fermé dans l'exemple ci-dessus.

si vous voulez un morceau (76 caractères) (en utilisant le codec commun) ...

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

Je suis très surpris que personne ici n'ait mentionné le problème de connexion et délai de lecture. Il peut arriver (en particulier sur Android et/ou avec une connectivité réseau merdique) que la demande se bloque et attende indéfiniment.

Le code suivant (qui utilise également Apache IO Commons) en tient compte et attend au maximum 5 secondes jusqu'à ce qu'il échoue:

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

La longueur du contenu n'est qu'un en-tête HTTP. Vous ne pouvez pas lui faire confiance. Lisez tout ce que vous pouvez dans le flux.

Disponible est définitivement faux. C'est juste le nombre d'octets qui peuvent être lus sans blocage.

Un autre problème est la gestion de vos ressources. La fermeture du flux doit se produire dans tous les cas. try/catch/enfin le fera.

1
Thomas Jung