2012-04-13 17 views
15

Ho un InputStream che voglio scritto su HttpServletResponse. C'è questo approccio, che impiega troppo tempo a causa dell'uso di byte []Scrive un InputStream a un HttpServletResponse

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

mi chiedevo cosa potrebbe essere il modo migliore per farlo, in termini di velocità ed efficienza.

risposta

41

Basta scrivere in blocchi invece di copiarli interamente nella memoria di Java prima. L'esempio di base sottostante lo scrive in blocchi di 10 KB. In questo modo si finisce con un utilizzo coerente della memoria di soli 10 KB anziché la lunghezza totale del contenuto. Anche l'utente finale inizierà a ottenere parti del contenuto molto prima.

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

Come creme de la creme per quanto riguarda le prestazioni, è possibile utilizzare NIO Channels e assegnato direttamente ByteBuffer. Creare il seguente metodo utility/helper in alcune classi di utilità personalizzate, ad es. 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; 
    } 
} 

che poi utilizzano come di seguito:

response.setContentLength(getContentLength()); 
Utils.stream(getInputStream(), response.getOutputStream()); 
+0

Speravo ci potesse essere un altro modo, ma grazie comunque –

+0

Grazie mille BalusC, –

+2

Naturalmente molti pacchetti di utilità hanno già definito questo metodo, quindi una volta iniziato a usare Guava ... http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/io /ByteStreams.html#copy(java.io.InputStream, java.io.OutputStream) –

1
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); 
} 
+0

I wan per evitare l'utilizzo di byte [], se possibile –

+0

@MuhammadSabry non c'è modo di leggere l'InputStream w/o utilizzando ' byte [] ' –

+0

Cosa c'è di sbagliato con il byte []. Devi archiviare i dati someware:} – MTilsted

0

Penso che sia molto vicino al modo migliore, ma vorrei suggerire il seguente cambiamento. Utilizzare un buffer di dimensioni fisse (dire 20K) e quindi eseguire la lettura/scrittura in un ciclo.

Per il ciclo fare qualcosa di simile

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: Il vostro programma non sempre funziona così com'è, perché in lettura non sempre riempire l'intero array si dà.

+0

cosa intendi esattamente per leggere non riempie l'intero array che gli dai? –

+1

La lettura non riempie sempre la matrice di input. Quindi è necessario controllare il valore che legge il ritorno che è il numero di byte letti. (Vedi http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read%28byte[]%29) – MTilsted

Problemi correlati