2011-01-10 20 views
14
ServletOutputStream output = response.getOutputStream(); 
output.write(byte[]); 

Jaki jest najbardziej skuteczny sposób zapisu pliku do javax.servlet.ServletOutputStream?Najbardziej skuteczny sposób zapisu pliku do ServletOutputStream

EDIT:

nie będzie to bardziej skuteczne, jeśli Nio użyto?

+0

nio nie jest magiczną kulą, która sprawia, że ​​wszystko dzieje się szybciej. w rzeczywistości nio jest generalnie przydatne, jeśli chcesz, aby Twój kod był bardziej skalowalny (np. mniej wątków obsługuje więcej połączeń). w przypadku kodu z pojedynczym gwintem, io jest prawie zawsze tak dobre lub lepsze (wyjątkiem od tej reguły może być przesyłanie plików do pliku). – jtahlborn

Odpowiedz

32
IOUtils.copy(in, out); 
out.flush(); 
//........... 
out.close(); // depends on your application 

Gdzie in jest FileInputStream i out jest SocketOutputStream. IOUtils to narzędzie z modułuw Apache Commons.

+6

+1, ale dwie uwagi - to "Apache commons", i można użyć 'IOUtils.closeQuitely (..)' – Bozho

+0

@Bozho kiedyś nazywano Jakarta Commons wiele lat temu :-) –

+0

, który nie działa dla ja, nie chcę dodawać słoika IO do Commons tylko dla tej funkcjonalności. – IAdapter

0

Jeśli nie chcesz dodawać słoika do aplikacji, musisz skopiować go ręcznie. Wystarczy skopiować wdrożenie metody stąd: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1004358&view=markup:

private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 

public static int copy(InputStream input, OutputStream output) throws IOException { 
    long count = copyLarge(input, output); 
    if (count > Integer.MAX_VALUE) { 
    return -1; 
    } 
    return (int) count; 
} 

public static long copyLarge(InputStream input, OutputStream output) 
    throws IOException { 
    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 
    long count = 0; 
    int n = 0; 
    while (-1 != (n = input.read(buffer))) { 
    output.write(buffer, 0, n); 
    count += n; 
    } 
    return count; 
} 

umieścić te 2 metod w jednej z klas pomocniczych i jesteś dobry, aby przejść.

+1

czy to nie będzie bardziej skuteczne, jeśli użyjesz NIO? – IAdapter

+1

Miałem mieszane wyniki z nio :). Może być lepiej, może nie. Kod jest zdecydowanie bardziej skomplikowany i naprawdę musisz przetestować wyniki na swoim komputerze, aby upewnić się, że jest wystarczająco dobry. Poszukaj kodu: http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/ –

+1

+1 ymmv, ale ciężko mi było zrobić nio wersja szybsza niż stare dobre strumienie –

3

Po pierwsze, nie ma to związku z serwletami. Dotyczy to ogólnie Java IO. Masz przecież tylko InputStream i OutputStream.

Jeśli chodzi o odpowiedź, nie jesteś jedynym, który się nad tym zastanawia. Na interwebs można znaleźć innych, którzy zastanawiali się takie same, ale miały starań, aby przetestować/benchmark to sami:

Ogólnie FileChannel z tablicy 256K bajtów który jest odczytywany przez owinięte ByteBuffer i zapisany bezpośrednio z tablicy bajtów jest najszybszym sposobem. Rzeczywiście, NIO.

FileInputStream input = new FileInputStream("/path/to/file.ext"); 
FileChannel channel = input.getChannel(); 
byte[] buffer = new byte[256 * 1024]; 
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); 

try { 
    for (int length = 0; (length = channel.read(byteBuffer)) != -1;) { 
     System.out.write(buffer, 0, length); 
     byteBuffer.clear(); 
    } 
} finally { 
    input.close(); 
} 
+0

Pierwsze łącze wydaje się polecać bufor 8K, ponieważ czas na skopiowanie różnic między 8 a 256K jest minimalny. Wydaje się to mieć sens, biorąc pod uwagę, że większość systemów plików nadal korzysta ze stron 4KB i klastrów dysków 4KB. – AngerClown

+0

Różnica jest rzeczywiście minimalna. OP domaga się jednak "skutecznej drogi", a nie "skutecznej drogi". 8K jest nadal szybki, ale zajmuje mniej pamięci w przypadku dużej ilości stron. – BalusC

+0

Co powiesz na używanie kanałów i Channel.transferTo? – IAdapter

4

Masz ServletOutputStream. Jedyny sposób, aby do tego napisać, to java.io. *. W ogóle nie możesz używać NIO (poza owijaniem przy pomocy Channels, co jest bezcelowe: wciąż jest pod nim OutputStream, a Ty dodajesz tylko przetwarzanie na wierzchu). Rzeczywiste operacje we/wy są związane z siecią, a zapisy są buforowane w każdym razie przez kontener serwletu (dzięki czemu można ustawić nagłówek Content-Length), więc szukanie poprawek wydajności tutaj jest bezcelowe.

+0

możesz użyć kanałów nio. – IAdapter

+8

@ 01: Tak, możesz użyć kanałów NIO, jeśli używasz Channels.newChannel (OutputStream). Który opakowuje strumień wyjściowy w kanale. Wciąż rozmawia z podstawowym ByteArrayOutputStream. W tej sytuacji nie ma poprawy wydajności. To jest bezcelowe. – EJP

+0

można używać NIO za pomocą kanałów NIO. –

Powiązane problemy