. ,, .,
Strumienie buforowane ;
Klasa Buf feredOutputStream przechowuje buforowane dane w buforze (chro-
nionej tablicy bajtów zwanej buf) do czasu, aż bufor się napełni lub strumień zosta-
nie opróżniony. Następnie zapisuje jednocześnie wszystkie dane na jej podstawo-
wym strumieniu wyjściowym. Jeden zapis wielu bajtów jest prawie zawsze szybszy
niż wiele małych zapisów, które dodają je porcjami. Szczególnie dotyczy to połączeń
sieciowych, ponieważ każdy segment TCP lub pakiet UDP przenosi skończoną ilość
danych narzutu, zazwyczaj wartą około 40 bajtów. A to oznacza, że przesłanie l kilo-
bajta danych po jednym bajcie wymaga wysłania kablem 40 kilobajtów, podczas gdy
wysłanie ich razem nieco ponad l kilobajt danych. Większość kart sieciowych i im-
plementacji TCP ma wbudowany pewien poziom buforowania, więc prawdziwe
statystyki nie są aż tak dramatyczne. Niemniej jednak buforowanie wyjścia siecio-
wego na ogół ogromnie poprawia wydajność.
90______________________________^ Rozdzia^Wejście^wyiście w Javie
Klasa Buf f eredlnputStream także posiada chronioną tablicę bajtów zwaną buf,
która służy jako bufor. Gdy wywoływana jest jedna z metod read () strumienia, to
najpierw próbuje ona pobrać żądane dane z bufora. Dopiero kiedy bufor opróżni się
z danych, strumień czyta z podstawowego źródła. W tym momencie wczytuje ze
źródła do bufora tyle danych, ile zdoła, niezależnie od tego, czy potrzebuje wszyst-
kich tych danych już teraz, czy nie. Dane, które nie zostaną wykorzystane natych-
miast, będą dostępne przy następnych wywołaniach metody read (). Przeczytanie
kilku tysięcy bajtów danych z podstawowego strumienia, jeśli pliki są czytane z dys-
ku lokalnego, jest prawie tak samo szybkie, jak wczytanie jednego bajta danych. Wi-
dać zatem, że buforowanie znacznie poprawia wydajność. Zysk jest mniej oczywisty
przy połączeniach sieciowych, gdzie często prędkość, przy której sieć może dostar-
czać dane, jest determinowana przez „korek" w sieci, a nie przez prędkość, z jaką in-
terfejs sieciowy dostarcza dane programowi, ani nie prędkość, z jaką działa pro-
gram. Pomimo tego buforowanie wejścia rzadko jest szkodliwe, a będzie stawać się
coraz istotniejsze, w miarę jak prędkość w sieci będzie rosła.
KlasaBuf f eredlnputStream ma dwa konstruktor)', podobnie jak Buf f eredOut-
putStream:
public BufferedlnputStream(InputStream in) .
public BufferedlnputStream(InputStream in, int bufferSize) .. :'
public BufferedOutputStream(OutputStream out)
public Buf feredOutputStream (OutputStream out, int bufferSize) .' •,. •
Pierwszy argument jest podstawowym strumieniem, z którego zostaną odczytane
niezbuforowane dane lub w którym zostaną zapisane buforowane dane. Drugi ar-
gument, jeśli jest określony, definiuje liczbę bajtów w buforze. W przeciwnym przy-
padku rozmiar bufora jest ustalany na 2048 bajtów dla strumienia wejściowego i 512
bajtów dla strumienia wyjściowego. Idealny rozmiar bufora zależy od rodzaju bufo-
rowanego strumienia. Dla połączeń sieciowych dobrze jest mieć bufor trochę więk-
szy od typowego rozmiaru pakietu. Jednak może to być trudne do przewidzenia
i zmieniać się w zależności od lokalnych połączeń sieciowych i protokołów. Szybsze
sieci o szerszym paśmie przenoszenia raczej używają większych pakietów, tak więc
8 kilobajtów jest w efekcie maksymalnym rozmiarem pakietu dla UDP w większości
współczesnych sieci, a segmenty TCP często mają nie więcej niż jeden kilobajt.
Klasa Buf feredlnputStream nie ma zadeklarowanych żadnych nowych,
własnych metod. Nadpisuje jedynie metody z klasy Ir.put.Stream. Obsługuje zna-
kowanie i cofanie. Na przykład:
public synchronized int read O throws IOExcepticr.
public synchronized int read (byte [ ] input, inr offset, int length)
throws IOException
public synchronized long skipdong n) throws ICEy.ception
public synchronized int available() throws IOExcepticn •'•'• •' • , •
public synchronized void mark(int readLimit) -.': ': '. • '.
public synchronized void resetO throws IOExcepticn
public boolean markSupported()
Począwszy od Javy 1.2, dwie wielobajtowe metody read () starają się kompletnie
wypełnić wybraną tablicę lub podtablicę danych, czytając z podstawowego strumie-
nia wejściowego tyle razy, ile jest to konieczne. Zwracają dane tylko wtedy, gdy ta-
Strumienie filtrujące_________________________________________97
blica lub podtablica została w całości wypełniona, koniec strumienia został osiągnię-
ty albo gdy podstawowy strumień zablokowałby się przy dalszych odczytach. Wię-
kszość strumieni wejściowych (w tym buforowany strumień wejściowy w Javie l .1 .x
i wcześniejszych) nie działa w opisany tu sposób. Czytają one z podstawowego stru-
jnienia lub źródła danych tylko jeden raz, zanim zaczną zwracać dane.
Klasa Buf f eredOutputStream także nie ma zadeklarowanych żadnych nowych,
własnych metod. Nadpisuje jedynie trzy metody z klasy OutputStream:
public synchronized void write(int b) throws IOException
public synchronized void write (byte [] data, int offset, int length) • '• ''
throws IOException -.;'
public synchronized void flushO throws IÓException
Wywołuje się te metody dokładnie tak samo jak w przypadku każdego innego stru-
mienia wyjściowego. Różnica polega na tym, że każda metoda write () umieszcza
dane w buforze, a nie bezpośrednio w podstawowym strumieniu wyjściowym. Dla-
tego tak istotne jest opróżnianie strumienia, gdy tylko można to zrobić.
Klasa PrintStream
Klasa PrintStream jest pierwszym wyjściowym strumieniem filtrującym, z któ-
rym spotyka się większość programistów, ponieważ strumień System, out jest
klasą PrintStream. Natomiast inne strumienie wyjściowe mogą być łańcuchowo
dołączane do strumieni drukujących za pomocą poniższych dwóch konstruktorów:
public PrintStream(OutputStream out)
public PrintStream(OutputStream out, boolean autoFlush)
Domyślnie strumienie drukujące powinny być w jawny sposób opróżniane. Jeśli jed-
nak argumentem autoFlush jest true, to strumień będzie opróżniany za każdym
razem, gdy zostanie zapisana tablica bajtów lub znak przesuwu o wiersz albo gdy
zostanie wywołana metoda println ().
Klasa PrintStream, oprócz typowych metod write (), f lush () iclose(),ma
dziewięć przedefiniowanych metod print () i dziesięć przedefiniowanych metod
println ():
public void print (boolean b) '• •''''' '*'
public void print(char c) • >'•'"'!••'"•»• -.•-:•' 7;"*Ś'TJ .-,,:.