2011-01-19 16 views
12

Quando ho voglia di scrivere l'intero contenuto di un file in un OutputStream, di solito allocare un buffer come byte[], poi fare un ciclo for ai dati read dal file di InputStream nel buffer e scrivere il contenuto del buffer nel OutputStream, fino a quando lo InputStream non ha più byte disponibili.Esiste un modo migliore per scrivere l'intero contenuto di un file in un OutputStream?

Questo mi sembra piuttosto maldestro. C'è un modo migliore per farlo?

Inoltre, non sono sempre sicuro della dimensione del buffer. Di solito, sto allocando 1024 byte, perché è semplicemente buono. C'è un modo migliore per determinare una dimensione del buffer ragionevole?

Nel mio caso corrente, voglio copiare l'intero contenuto di un file nel flusso di output che scrive il contenuto di una risposta HTTP. Quindi, questa non è una domanda su come copiare i file sul file system.

risposta

19

Per Java 1.7+ è possibile utilizzare Files.copy(Path, OutputStream), ad es.

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

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

nota, dal momento che si tratta di HttpServletResponse è è anche una buona idea per impostare intestazioni di risposta corretta. Aggiungere le seguenti righe prima di copiare i dati del file effettivi alla risposta:

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 codifica del nome del file passato alla disposizione contenuto è importante, vedi this question.

+0

In che modo il mio test dell'unità può verificare cosa viene scritto su OutputStream? ServletOutputStream mockOutput = mock (ServletOutputStream.class); \t \t when (response.getOutputStream()). ThenReturn (mockOutput); –

8

Con commons-io si dispone di una soluzione one-line:

IOUtils.copy(yourFileInputStream, outputStream); 

Nota che avresti dovuto chiudere i flussi manualmente (o con IOUtils.closeQuitely(..))

+0

Questo sarebbe il mio suggerimento. Anche se quello che fa è la stessa cosa. – rfeak

+0

sì, solo più corto. E buffer automaticamente – Bozho

+0

Che sembra davvero bello. Ma per questo semplice compito, mi sembra un po 'esagerato includere un'altra libreria. Naturalmente, se ci sono più motivi per includere Commons-IO, questa sarà la soluzione di scelta. – Madoc

21

Apache Commons-IO:

IOUtils.copy(fileInputStream,outputStream); 

JDK NIO

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

+1 per NIO .... – Bozho

+0

Wow. Ho dato un breve commento riguardo a Commons-IO alla risposta di Bozho. Ma la soluzione del canale è esattamente quello che stavo cercando. Grazie mille, tutti i canali NIO mi hanno superato, perché avevo già imparato Java IO prima che esistesse NIO. E, a proposito: 9 minuti! È quasi veloce come un fulmine. – Madoc

+2

non dimenticare di chiudere 'FileInputStream' – yegor256

Problemi correlati