2011-01-19 12 views
12

Cuando quiero escribir todo el contenido de un archivo en un OutputStream, por lo general asignar un búfer como byte[], a continuación, hacer un bucle for a read datos del archivo de InputStream en el búfer y escribir el contenido del búfer en el OutputStream, hasta que el InputStream no tenga más bytes disponibles.¿Existe alguna forma mejor de escribir el contenido completo de un archivo en un OutputStream?

Esto me parece bastante torpe. ¿Hay una mejor manera de hacer esto?

Además, no estoy seguro del tamaño del búfer. Por lo general, estoy asignando 1024 bytes, porque se siente bien. ¿Hay una mejor manera de determinar un tamaño de búfer razonable?

En mi caso actual, quiero copiar el contenido completo de un archivo en la secuencia de salida que escribe el contenido de una respuesta HTTP. Por lo tanto, esta no es una pregunta sobre cómo copiar archivos en el sistema de archivos.

Respuesta

19

Para Java 1.7+ puede usar Files.copy(Path, OutputStream), p. Ej.

HttpServletResponse response = // ... 
File toBeCopied = // ... 

try (OutputStream out = response.getOutputStream()) { 
    Path path = toBeCopied.toPath(); 
    Files.copy(path, out); 
    out.flush(); 
} catch (IOException e) { 
    // handle exception 
} 

Tenga en cuenta, ya que se trata de HttpServletResponse es también es una buena idea establecer cabeceras de respuesta correctas. Añadir las siguientes líneas antes de copiar los datos de los archivos reales de la respuesta:

String mimeType = URLConnection.guessContentTypeFromName(toBeCopied.getName()); 
String contentDisposition = String.format("attachment; filename=%s", toBeCopied.getName()); 
int fileSize = Long.valueOf(toBeCopied.length()).intValue(); 

response.setContentType(mimeType); 
response.setHeader("Content-Disposition", contentDisposition); 
response.setContentLength(fileSize); 

Nota, la codificación del nombre de archivo se pasa a la disposición de contenido es importante, ver this question.

+0

¿Cómo podría verificar mi unidad lo que se está escribiendo en OutputStream? ServletOutputStream mockOutput = mock (ServletOutputStream.class); \t \t when (response.getOutputStream()). ThenReturn (mockOutput); –

8

Con commons-io tiene una solución de una sola línea:

IOUtils.copy(yourFileInputStream, outputStream); 

Tenga en cuenta que tendría que cerrar los flujos manualmente (o por IOUtils.closeQuitely(..))

+0

Esta sería mi sugerencia también. Aunque lo que hace es lo mismo. – rfeak

+0

sí, solo más corto. Y buffers automáticamente – Bozho

+0

Eso se ve muy bien. Pero para esta simple tarea, parece un poco exagerado para mí incluir otra biblioteca. Por supuesto, si hay más razones para incluir Commons-IO, esta será la solución de elección. – Madoc

21

Apache Commons-IO:

IOUtils.copy(fileInputStream,outputStream); 

JDK NIO

new FileInputStream(file).getChannel().transferTo(otherChannel); 
+3

+1 para NIO .... – Bozho

+0

Wow. Hice un breve comentario sobre Commons-IO en la respuesta de Bozho. Pero la solución de canal es exactamente lo que estaba buscando. Muchas gracias, todos los canales de NIO me pasaron, porque ya había aprendido Java IO antes de que existiera NIO. Y, por cierto: ¡9 minutos! Eso es casi tan rápido como un rayo. – Madoc

+2

no se olvide de cerrar 'FileInputStream' – yegor256

Cuestiones relacionadas