2011-01-19 17 views
12

Gdy chcę napisać całą zawartość pliku do o OutputStream, zwykle przydziela bufor jako byte[], a następnie dokonać for pętli read danych z pliku na InputStream do bufora i zapis zawartości bufora do OutputStream, do momentu, gdy InputStream nie ma więcej bajtów.Czy istnieje lepszy sposób zapisu pełnej zawartości pliku do OutputStream?

Wydaje mi się to dość niezdarne. Czy jest lepszy sposób to zrobić?

Ponadto, zawsze jestem pewien rozmiaru bufora. Zazwyczaj przydzielam 1024 bajty, ponieważ po prostu dobrze się czuję. Czy istnieje lepszy sposób określenia rozsądnego rozmiaru bufora?

W moim bieżącym przypadku chcę skopiować pełną zawartość pliku do strumienia wyjściowego, który zapisuje zawartość odpowiedzi HTTP. Nie jest to więc kwestia kopiowania plików w systemie plików.

Odpowiedz

19

W przypadku Javy 1.7+ można użyć numeru Files.copy(Path, OutputStream), np.

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

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

Note, ponieważ masz do czynienia z HttpServletResponse jest to również dobry pomysł, aby ustawić odpowiednie nagłówki odpowiedzi. Dodaj poniższe linie przed ty skopiowania danych rzeczywistych plików do odpowiedzi:

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

pamiętać, że kodowanie nazwy pliku przekazany do dyspozycji treść jest ważna, patrz this question.

+0

W jaki sposób mój test jednostki może sprawdzić, co jest zapisywane w OutputStream? ServletOutputStream mockOutput = mock (ServletOutputStream.class); \t \t when (response.getOutputStream()). ThenReturn (mockOutput); –

8

Z commons-io masz rozwiązanie jedną linię:

IOUtils.copy(yourFileInputStream, outputStream); 

Należy pamiętać, że trzeba by ręcznie zamknąć strumienie (lub IOUtils.closeQuitely(..))

+0

To też byłaby moja sugestia. Chociaż to, co robi, jest tym samym. – rfeak

+0

tak, tylko krótszy. I bufory automatycznie – Bozho

+0

To wygląda naprawdę ładnie. Ale w przypadku tego prostego zadania wydaje mi się nieco przesadzone, że mogę dołączyć do innej biblioteki. Oczywiście, jeśli jest więcej powodów, aby dołączyć Commons-IO, to będzie to rozwiązanie z wyboru. – Madoc

21

Apache Commons IO:

IOUtils.copy(fileInputStream,outputStream); 

JDK NIO

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

+1 dla NIO .... – Bozho

+0

Wow. Zrobiłem krótki komentarz dotyczący Commons-IO w odpowiedzi Bozho. Ale rozwiązanie kanału jest dokładnie tym, czego szukałem. Wielkie dzięki, wszystkie kanały NIO minęły mnie, ponieważ nauczyłem się już Java IO zanim NIO istniało. A przy okazji: 9 minut! To prawie tak szybko, jak błyskawica. – Madoc

+2

nie zapomnij zamknąć 'FileInputStream' – yegor256

Powiązane problemy