web-dev-qa-db-fra.com

Écrire un InputStream dans un HttpServletResponse

J'ai un InputStream que je veux écrire dans un HttpServletResponse. Il y a cette approche, qui prend trop de temps en raison de l'utilisation de l'octet []

InputStream is = getInputStream();
int contentLength = getContentLength();

byte[] data = new byte[contentLength];
is.read(data);

//response here is the HttpServletResponse object
response.setContentLength(contentLength);
response.write(data);

Je me demandais quelle pourrait être la meilleure façon de le faire, en termes de vitesse et d'efficacité.

18
Sabry Shawally

Il suffit d'écrire en blocs au lieu de le copier entièrement dans la mémoire de Java en premier. L'exemple de base ci-dessous l'écrit en blocs de 10 Ko. De cette façon, vous vous retrouvez avec une utilisation cohérente de la mémoire de seulement 10 Ko au lieu de la longueur totale du contenu. L'utilisateur final commencera également à obtenir des parties du contenu beaucoup plus tôt.

response.setContentLength(getContentLength());
byte[] buffer = new byte[10240];

try (
    InputStream input = getInputStream();
    OutputStream output = response.getOutputStream();
) {
    for (int length = 0; (length = input.read(buffer)) > 0;) {
        output.write(buffer, 0, length);
    }
}

En tant que crème de la crème en ce qui concerne les performances, vous pouvez utiliser NIO Channels et un directement alloué ByteBuffer . Créez la méthode utilitaire/d'assistance suivante dans une classe d'utilitaire personnalisée, par exemple Utils:

public static long stream(InputStream input, OutputStream output) throws IOException {
    try (
        ReadableByteChannel inputChannel = Channels.newChannel(input);
        WritableByteChannel outputChannel = Channels.newChannel(output);
    ) {
        ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
        long size = 0;

        while (inputChannel.read(buffer) != -1) {
            buffer.flip();
            size += outputChannel.write(buffer);
            buffer.clear();
        }

        return size;
    }
}

Que vous utilisez ensuite comme ci-dessous:

response.setContentLength(getContentLength());
Utils.stream(getInputStream(), response.getOutputStream());
45
BalusC
BufferedInputStream in = null;
BufferedOutputStream out = null;
OutputStream os;
os = new BufferedOutputStream(response.getOutputStream());
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(os);
byte[] buffer = new byte[1024 * 8];
int j = -1;
while ((j = in.read(buffer)) != -1) {
    out.write(buffer, 0, j);
}
1
shenli3514

Je pense que c'est très proche de la meilleure façon, mais je suggérerais le changement suivant. Utilisez un tampon de taille fixe (disons 20K), puis effectuez la lecture/écriture en boucle.

Pour la boucle, faites quelque chose comme

byte[] buffer=new byte[20*1024];
outputStream=response.getOutputStream();
while(true) {
  int readSize=is.read(buffer);
  if(readSize==-1)
    break;
  outputStream.write(buffer,0,readSize);
}

ps: Votre programme ne fonctionnera pas toujours tel quel, car read ne remplit pas toujours tout le tableau que vous lui donnez.

0
MTilsted