2012-04-13 19 views
15

Tengo un InputStream que quiero que se escriba en un HttpServletResponse. Hay este enfoque, que lleva demasiado tiempo debido a la utilización de byte []Escribir un InputStream en 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); 

Me preguntaba lo que podría ser la mejor manera de hacerlo, en términos de velocidad y eficiencia.

Respuesta

41

Simplemente escriba en bloques en lugar de copiarlo por completo en la memoria de Java primero. El ejemplo básico a continuación lo escribe en bloques de 10 KB. De esta forma, se obtiene un uso de memoria constante de solo 10 KB en lugar de la longitud completa del contenido. Además, el usuario final comenzará a obtener partes del contenido mucho antes.

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

Como crema de la crema en relación con el rendimiento, se puede usar NIO Channels y directamente asignado ByteBuffer. Cree el siguiente método de utilidad/ayuda en alguna clase de utilidad personalizada, p. 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 luego se utiliza de la siguiente manera:

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

Esperaba que pudiera haber otra forma, pero gracias de todos modos –

+0

Muchas gracias BalusC, –

+2

Por supuesto, muchos paquetes de utilidades ya tienen este método definido, así que una vez que comiences a usar 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 para evitar el uso de byte [], si es posible –

+0

@MuhammadSabry no hay manera de leer InputStream w/o el uso de ' byte [] ' –

+0

¿Qué pasa con byte []. Necesita almacenar los datos de algunosware:} – MTilsted

0

Creo que está muy cerca de la mejor manera, pero sugeriría el siguiente cambio. Use un búfer de tamaño fijo (digamos 20K) y luego haga la lectura/escritura en un bucle.

para el bucle de hacer algo como

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: Su programa no siempre funcionará como es, porque de lectura no siempre se llenan toda la matriz que le des.

+0

¿a qué se refiere exactamente con "leer" que no llena toda la matriz que le da? –

+1

La lectura no siempre llena la matriz de entrada. Por lo tanto, debe verificar el valor que devuelve la lectura, que es el número de bytes leídos. (Ver http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read%28byte[]%29) – MTilsted

Cuestiones relacionadas