web-dev-qa-db-fra.com

Le moyen le plus efficace de convertir InputStream en byte []?

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
ArrayList<Byte> arrayList = new ArrayList<Byte>();
try {
    while (responseStream.available() > 0) {
        arrayList.add(responseStream.readByte());
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
Iterator<Byte> iterator = arrayList.iterator();
byte[] bytes = new byte[arrayList.size()];
int i = 0;
while (iterator.hasNext()) {
    bytes[i++] = iterator.next();
}

Ce code est appelé à chaque chargement de page de mon application Web. Il semble fonctionner assez vite, mais y a-t-il quelque chose qui pourrait rendre cette course plus rapide?

Edit - Mise à jour à l'aide du flux de sortie de tableau d'octets

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
    int read = responseStream.read();
    while (read != -1) {
        byteArrayOutputStream.write(read);
        read = responseStream.read();
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
byte[] bytes = byteArrayOutputStream.toByteArray();
return ok(bytes).as(response.getHeader("Content-type"));

Edit - Code de test de référence

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
long t1 = System.nanoTime();

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
    int read = responseStream.read();
    while (read != -1) {
        byteArrayOutputStream.write(read);
        read = responseStream.read();
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
byte[] bytes = byteArrayOutputStream.toByteArray();

long t2 = System.nanoTime();
System.out.println(t2-t1);
return ok(bytes).as(response.getHeader("Content-type"));

Durée moyenne après 100+ requête - 46873

ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
long t1 = System.nanoTime();

ArrayList<Byte> arrayList = new ArrayList<Byte>();
try {
    while (responseStream.available() > 0) {
        arrayList.add(responseStream.readByte());
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
Iterator<Byte> iterator = arrayList.iterator();
byte[] bytes = new byte[arrayList.size()];
int i = 0;
while (iterator.hasNext()) {
    bytes[i++] = iterator.next();
}

long t2 = System.nanoTime();
System.out.println(t2-t1);
return ok(bytes).as(response.getHeader("Content-type"));

Durée moyenne après 100+ requête - 522848

long t1 = System.nanoTime();
byte[] bytes;
try {
    bytes = org.Apache.commons.io.IOUtils.toByteArray(responseStream);
} catch (Exception e) {
    return internalServerError();
}

long t2 = System.nanoTime();
System.out.println(t2-t1);

Durée moyenne après 100+ requête - 45088

long t1 = System.nanoTime();
byte[] bytes;
try {
    bytes = Sun.misc.IOUtils.readFully(responseStream, -1, true);
} catch (Exception e) {
    return internalServerError();
}

long t2 = System.nanoTime();
System.out.println(t2 - t1);

Délai moyen après 100 requêtes + - 20180

11
sissonb

Oui. Utilisez une ByteArrayOutputStream plutôt qu'une ArrayList. Ensuite, lisez des fragments d'octets dans InputStream (sans utiliser available(), qui ne devrait presque jamais être utilisé) et écrivez ces fragments dans ByteArrayOutputStream, jusqu'à ce que la méthode read() renvoie -1. Ensuite, appelez toByteArray () sur votre ByteArrayOutputStream.

Vous pouvez utiliser la méthode ByteStreams.toByteArray() de Guava, qui fait tout cela pour vous, ou lire son code source pour avoir une meilleure idée de la façon dont il le fait. Lire le didacticiel IO pourrait également aider.

13
JB Nizet

Quel est le problème avec Apache Commons IO IOUtils.toByteArray method? Cela a été optimisé pendant de nombreuses années à cette fin.

4
bmargulies

Pourquoi? Ce code est entièrement équivalent à read(byte[]), sauf qu'il effectue deux étapes de copie supplémentaires sur l'ensemble des données. Tu n'as pas besoin de ça. Un simple read(byte[]) serait plusieurs fois plus rapide.

L'utilisation de available() est également invalide. Vous avez besoin de la totalité de la réponse, pas seulement de la partie pouvant être lue sans blocage. Vous devez faire une boucle.

1
user207421