Você está na página 1de 94

Java.

Techniki zaawansowane.
Wydanie VIII
Autor: Cay S. Horstmann, Gary Cornell
T³umaczenie: Jaromir Senczyk
ISBN: 978-83-246-1483-7
Tytu³ orygina³u: Core Java(tm),
Volume II--Advanced Features:
Eighth Edition
Format: 172x245, stron: 1064
• Jak wykorzystaæ strumienie?
• Jak stworzyæ efektowny interfejs u¿ytkownika?
• Jak zapewniæ bezpieczeñstwo w tworzonych aplikacjach?
Co spowodowa³o, ¿e jêzyk programowania Java zyska³ tak wielk¹ popularnoœæ?
Przyczyn jest kilka: mo¿liwoœæ przenoszenia kodu miêdzy programami, wydajnoœæ i to,
co programiœci lubi¹ najbardziej – mechanizm automatycznego oczyszczania pamiêci.
Nie bez znaczenia jest równie¿ to, ¿e Java jest jêzykiem zorientowanym obiektowo,
udostêpnia obs³ugê programowania rozproszonego oraz œwietn¹ dokumentacjê.
Ponadto liczne publikacje oraz pomocna spo³ecznoœæ sprawiaj¹, ¿e Java zajmuje
poczesne miejsce wœród innych jêzyków programowania.
Kolejne wydanie ksi¹¿ki „Java. Techniki zaawansowane. Wydanie VIII” zosta³o
zaktualizowane o wszystkie te elementy, które pojawi³y siê w wersji szóstej platformy
Java Standard Edition. Dziêki tej ksi¹¿ce dowiesz siê, w jaki sposób wykorzystaæ
strumienie, jak parsowaæ dokumenty XML czy te¿ w jaki sposób tworzyæ aplikacje
sieciowe. Poznasz interfejs JDBC, sposób wykorzystania transakcji oraz wykonywania
zapytañ SQL. Autorzy w szczegó³owy sposób poka¿¹ Ci, jak tworzyæ aplikacje
z wykorzystaniem biblioteki Swing. Dodatkowo przedstawi¹, w jaki sposób zapewniæ
bezpieczeñstwo w tworzonych przez Ciebie aplikacjach. Wszystkie te – oraz wiele
innych – zagadnienia zostan¹ przedstawione w przystêpny i sprawdzony sposób!
• Wykorzystanie strumieni
• Dokumenty XML i ich wykorzystanie w jêzyku Java
• Programowanie aplikacji sieciowych
• Wykorzystanie interfejsu JDBC
• Tworzenie aplikacji wielojêzycznych
• Mo¿liwoœci pakietu Swing
• Wykorzystanie biblioteki AWT
• Bezpieczeñstwo w aplikacjach
• Zastosowanie podpisu cyfrowego
• Sposoby wykorzystania obiektów rozproszonych (RMI)
Wykorzystaj zaawansowane mo¿liwoœci jêzyka Java w swoich projektach!

Spis treci
Przedmowa ...............................................................................................................................................11
Podzikowania .........................................................................................................................................15
Rozdzia 1. Strumienie i pliki ....................................................................................................................17
Strumienie ................................................................................................................... 17
Odczyt i zapis bajtów ............................................................................................... 18
Zoo pene strumieni ................................................................................................ 20 
czenie filtrów strumieni ........................................................................................ 24
Strumienie tekstowe ..................................................................................................... 27
Zapisywanie tekstu ................................................................................................. 28
Wczytywanie tekstu ................................................................................................. 31
Zapis obiektów w formacie tekstowym ...................................................................... 31
Zbiory znaków ......................................................................................................... 35
Odczyt i zapis danych binarnych ..................................................................................... 40
Strumienie plików o swobodnym dostpie ................................................................. 43
Strumienie plików ZIP ................................................................................................... 48
Strumienie obiektów i serializacja .................................................................................. 55
Format pliku serializacji obiektów ............................................................................. 61
Modyfikowanie domylnego mechanizmu serializacji .................................................. 67
Serializacja singletonów i wylicze ............................................................................ 70
Wersje ................................................................................................................... 71
Serializacja w roli klonowania ................................................................................... 73
Zarzdzanie plikami ...................................................................................................... 75
Ulepszona obsuga wejcia i wyjcia .............................................................................. 82
Mapowanie plików w pamici ................................................................................... 82
Struktura bufora danych .......................................................................................... 89
Blokowanie plików ................................................................................................... 91
Wyraenia regularne ..................................................................................................... 93

Rozdzia 2. Jzyk XML ...........................................................................................................................103
Wprowadzenie do jzyka XML ...................................................................................... 104
Struktura dokumentu XML ..................................................................................... 106
Parsowanie dokumentów XML ..................................................................................... 109

4

Java. Techniki zaawansowane
Kontrola poprawnoci dokumentów XML ...................................................................... 120
Definicje typów dokumentów .................................................................................. 122
XML Schema ........................................................................................................ 129
Praktyczny przykad ............................................................................................... 131
Wyszukiwanie informacji i XPath .................................................................................. 145
Przestrzenie nazw ....................................................................................................... 151
Parsery strumieniowe ................................................................................................. 154
Wykorzystanie parsera SAX .................................................................................... 154
Wykorzystanie parsera StAX ................................................................................... 159
Tworzenie dokumentów XML ....................................................................................... 163
Tworzenie dokumentu XML za pomoc parsera StAX ................................................ 167
Przeksztacenia XSL ................................................................................................... 174

Rozdzia 3. Programowanie aplikacji sieciowych ...............................................................................185
Poczenia z serwerem ............................................................................................... 185
Limity czasu gniazd ............................................................................................... 190
Adresy internetowe ............................................................................................... 191
Implementacja serwerów ............................................................................................ 193
Obsuga wielu klientów .......................................................................................... 196
Poczenia czciowo zamknite ............................................................................ 200
Przerywanie dziaania gniazd sieciowych .................................................................. 201
Wysyanie poczty elektronicznej ................................................................................... 207
Poczenia wykorzystujce URL .................................................................................... 212
URL i URI ............................................................................................................. 212
Zastosowanie klasy URLConnection do pobierania informacji ................................... 214
Wysyanie danych do formularzy ............................................................................. 224

Rozdzia 4. Poczenia do baz danych: JDBC .......................................................................................233
Architektura JDBC ...................................................................................................... 234
Typy sterowników JDBC ......................................................................................... 235
Typowe zastosowania JDBC ................................................................................... 236
Jzyk SQL .................................................................................................................. 237
Instalacja JDBC .......................................................................................................... 243
Adresy URL baz danych ......................................................................................... 243
Pliki JAR zawierajce sterownik .............................................................................. 244
Uruchamianie bazy danych ..................................................................................... 244
Rejestracja klasy sterownika .................................................................................. 245
Nawizywanie poczenia z baz danych ................................................................. 246
Wykonywanie polece jzyka SQL ........................................................................... 248
Zarzdzanie poczeniami, poleceniami i zbiorami wyników ....................................... 251
Analiza wyjtków SQL ............................................................................................ 252
Wypenianie bazy danych ....................................................................................... 255
Wykonywanie zapyta ................................................................................................. 258
Polecenia przygotowane ........................................................................................ 259
Odczyt i zapis duych obiektów ............................................................................... 267
Sekwencje sterujce ............................................................................................. 269
Zapytania o wielu zbiorach wyników ........................................................................ 270
Pobieranie wartoci kluczy wygenerowanych automatycznie ...................................... 271
Przewijalne i aktualizowalne zbiory wyników zapyta ...................................................... 272
Przewijalne zbiory wyników ..................................................................................... 272
Aktualizowalne zbiory rekordów .............................................................................. 274

........................... 350 Klasy kompletów zasobów ................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... 335 Moc uporzdkowania ........................................................................................................... 421 Najprostsze drzewa ........................................................ 351 Kompletny przykad ....................................................................... 279 Buforowane zbiory rekordów ................ 438 Rysowanie wzów ........................... 295 Zaawansowane zarzdzanie poczeniami ...................................................................................................................................Spis treci 5 Zbiory rekordów .................................... 386 Modele tabel ....................................................................................... 459 Sformatowane pola wejciowe ........................ 374 Wstawianie i usuwanie ................................... Internacjonalizacja .................... 328 Porzdek alfabetyczny ............................................................................ 348 Lokalizacja zasobów ............................ 386 Najprostsze tabele ............................................................................................................. 487 ......................................................................................................... 367 Komponent JList . 292 Punkty kontrolne .......................................................................... 368 Modele list .......................... 379 Odrysowywanie zawartoci listy ............................................................... 394 Drzewa ... 299 Dostp do informacji katalogu LDAP ...................................................................................................................................................................................................... 282 Transakcje ............................ 353 Rozdzia 6........... 381 Tabele .............................................................................................................................................................................................................................. 450 Komponenty tekstowe ................................................................................................................................................................................................................................................................................ 458 ledzenie zmian zawartoci komponentów tekstowych .......................... 440 Nasuchiwanie zdarze w drzewach ..................................................................................................................................................................................................................................................................................... 390 Wiersze i kolumny ............... 326 Data i czas ......................................................................................................................................................................................................................... 337 Formatowanie komunikatów .......... 343 Formatowanie z wariantami ............................ 349 Pliki waciwoci .................................................................................................................... 298 Konfiguracja serwera LDAP ............................................................. 422 Przegldanie wzów .................. 337 Rozkad .............................................................................................................................................................................................. 293 Aktualizacje wsadowe ........................ 463 Komponent JSpinner ....................................... 345 Pliki tekstowe i zbiory znaków .................................................................................................................... 279 Metadane ........315 Lokalizatory ......................................................................... 321 Waluty ................................................... 443 Wasne modele drzew ................................................. 316 Formaty liczb ............................................................................................................ 479 Prezentacja HTML za pomoc JEditorPane ....................................................................................................................................................................367 Listy ............................................................................................................................. Zaawansowane moliwoci pakietu Swing ........................................................................................................................................ 293 Zaawansowane typy jzyka SQL ..................... 347 Komplety zasobów ......................................................................................... 303 Rozdzia 5............................ 297 Wprowadzenie do LDAP ............................................................................................................................................ 347 Internacjonalizacja a pliki ródowe programów ..................................................

.....................6 Java....................................................................... 652 Wykorzystanie lokalnego schowka do przekazywania referencji obiektów ............................................................................................................. 542 Pola ............................................................................................................................................ 638 Schowek .............................................................................................................................................. 587 Wykorzystanie obiektów zapisu i odczytu plików graficznych .............................................................................................. 538 Figury .................................................................................... 507 Panele z zakadkami ............................................................................................... 598 Filtrowanie obrazów ............................................................................................................................................................................................................. 624 Usugi drukowania ......................................................................... 581 Czytanie i zapisywanie plików graficznych .............................................. 564 Przeksztacenia ukadu wspórzdnych .................................................................................................................... 650 Przekazywanie obrazów za pomoc schowka ........................................................................................................................................................................................................................ 661 Mechanizm „przecignij i upu ” ........................................................................................................................................................... 613 Drukowanie grafiki ................................................. 633 Usugi drukowania za porednictwem strumieni ................................................ Techniki zaawansowane Wska niki postpu .................................................................................................................................................................................................................. 540 Wykorzystanie klas obiektów graficznych ............................................... 566 Przycinanie ...................................... 511 Panele pulpitu i ramki wewntrzne .................... 556 Wypenienia .......................................... Zaawansowane moliwoci biblioteki AWT ....................................... 588 Odczyt i zapis plików zawierajcych sekwencje obrazów ........................................................................ 518 Rozmieszczenie kaskadowe i ssiadujce ............................................................................................................................................................................................ 614 Drukowanie wielu stron ..................................... 521 Zgaszanie weta do zmiany waciwoci ................. 555 lad pdzla .................................................................................................. 507 Panele dzielone ................................................................................................................ 637 Atrybuty drukowania ................................................................................. 494 Monitory postpu .................................. 573 Wskazówki operacji graficznych ................... 657 Zastosowanie lokalnego schowka do przekazywania referencji obiektów ........................................................................ 501 Organizatory komponentów ...................537 Potokowe tworzenie grafiki ...... 604 Drukowanie .................... 662 Przekazywanie danych pomidzy komponentami Swing .... 494 Paski postpu ..... 646 Interfejs Transferable i formaty danych ................................................................................................................................................................ 664 ........................ 592 Operacje na obrazach .... 498 Monitorowanie postpu strumieni wejcia ........................................... 657 Wykorzystanie schowka systemowego do przekazywania obiektów Java ........... 598 Dostp do danych obrazu ........................................................................ 644 Klasy i interfejsy umoliwiajce przekazywanie danych ............................................. 623 Podgld wydruku ................................................................................. 645 Przekazywanie tekstu ...................................... 571 Przezroczysto i skadanie obrazów .................................................................................................................................................... 529 Rozdzia 7...................................................

...róda przeciganych danych .............. 678 Uruchamianie macierzystych aplikacji pulpitu .............................................................................. 683 Zasobnik systemowy .................................................................................................... 688 ......... 678 Ekran powitalny ........... 667 Cele upuszczanych danych .............. 670 Integracja z macierzyst platform .............................................................................................................................................................................................................................................................................

....................................... 719 Edytory waciwoci ........................................................................................................................ 710 Waciwoci ograniczone ................................... 733 Implementacja klasy indywidualizacji ..................................................................................................693 Dlaczego ziarnka? ......................................................................... 768 Implementacja wasnej procedury adujcej ...... 735 Trwao ziarnek JavaBeans ................................................ Bezpieczestwo ..................... 712 Klasa informacyjna ziarnka ....................................................... 705 Typy waciwoci ziarnek ............................................................................................................................ 742 Zastosowanie mechanizmu trwaoci JavaBeans dla dowolnych danych ..............................................................................Spis treci 7 Rozdzia 8.... 835 Szyfrowanie ........................................................................................................... 779 Bezpieczestwo na platformie Java ............ 822 Weryfikacja podpisu ........................................................................................................... 774 Menedery bezpieczestwa i pozwolenia ...................................................... 829 Podpisywanie kodu ....................... 784 Tworzenie wasnych klas pozwole ........................................................................ 699 Korzystanie z ziarnek ......................................................................................... 696 Wykorzystanie ziarnek do tworzenia aplikacji .............................................................................. 700 Wzorce nazw waciwoci ziarnek i zdarze . 769 Weryfikacja kodu maszyny wirtualnej ...................................................................................................................................................... JavaBeans ..... 830 Podpisywanie plików JAR ............... 726 Indywidualizacja ziarnka .......... 798 Moduy JAAS .................................................................................................................. 766 Zastosowanie procedur adujcych w roli przestrzeni nazw ....................... 839 Strumienie szyfrujce .. 837 Generowanie klucza .......................................................509 ............................................................................................................................................................................. 694 Proces tworzenia ziarnek JavaBeans ....................................................... 843 Szyfrowanie kluczem publicznym ................. 814 Podpisywanie wiadomoci ................. 746 Kompletny przykad zastosowania trwaoci JavaBeans ...................................................................................................................................................... 781 Pliki polityki bezpieczestwa ........... 698 Umieszczanie ziarnek w plikach JAR ................................................................................................................................................................................................................................................................. 764 Hierarchia klas adowania .............................................................................................................................................................................. 709 Waciwoci proste ........... 844 .......................................................................................................... 752 Rozdzia 9................................................................................................................... 790 Implementacja klasy pozwole ..................................................................................................... 830 Certyfikaty twórców oprogramowania .......................................................................................................................................................................................................................... 825 Podpisywanie certyfikatów ........... 837 Szyfrowanie symetryczne .........763 adowanie klas ................................................................................................................................................................................................................................................................ 804 Podpis cyfrowy ...... 823 Problem uwierzytelniania ................ 813 Skróty wiadomoci .................................................................................................................................................................................... 710 Waciwoci powizane ................................................. 722 Implementacja edytora waciwoci .......... 820 Certyfikaty X................ 792 Uwierzytelnianie uytkowników ......................................................................................................................................................................................................................................................................................................................... 709 Waciwoci indeksowane ............................................................................................................................................................................................................... 827 dania certyfikatu .......................................

.......... hashCode oraz clone ........................................................................................................................................................................................................................................... 858 Przygotowanie wdroenia ................................................................................................................... 854 Namiastka i szeregowanie parametrów ............................... 868 Zdalne referencje obiektów o wielu interfejsach .............................................................................................................................................893 Skrypty na platformie Java ............................. 905 Kompilacja w najprostszy sposób ... 866 Przekazywanie obiektów zdalnych ................................................................................................ 927 Adnotacje zarzdzania zasobami .......................................................................................................................................................................................................................................... 928 Przetwarzanie adnotacji w kodzie ródowym .......................... Metody macierzyste ...................................................................................................................................................................................... 854 Model programowania RMI .......................... 906 Stosowanie zada kompilacji .......................................................................... 943 Rozdzia 12.................................. 861 Rejestrowanie aktywnoci RMI .................................................... 911 Stosowanie adnotacji ..... 937 Modyfikacja kodu bajtowego podczas adowania ............................................................... 866 Przekazywanie obiektów...................................................................................................851 Role klienta i serwera . 918 Skadnia adnotacji ........................................... 931 Inynieria kodu bajtowego ......... 965 ..... 881 Klient usugi Web ................................................... 873 Zdalne obiekty i metody equals........................................................8 Java........................................... 900 Przykad: skrypty i graficzny interfejs uytkownika ..... 866 Dynamiczne adowanie klas .. 956 Dostp do skadowych obiektu ...................................... Techniki zaawansowane Rozdzia 10.................................... 897 Wywoywanie funkcji i metod skryptów . 961 Dostp do pól instancji ................... 955 acuchy znaków jako parametry ............................... kompilacja i adnotacje ...... 884 Usuga Amazon .......................................................................................... 948 Numeryczne parametry metod i wartoci zwracane ....................................................... 922 Adnotacje standardowe ...........................947 Wywoania funkcji jzyka C z programów w jzyku Java .......................................... Skrypty............................................................................................................................................................................................................................................................ 893 Wybór silnika skryptów ............................................................................ 898 Kompilacja skryptu .................................................................................................. 852 Wywoania zdalnych metod ........................ które nie s zdalne ......................................................................................................... 856 Interfejsy i implementacje ................... 962 Dostp do pól statycznych .................................................................................................................................................................................................................................. 856 Rejestr RMI ................. 901 Interfejs kompilatora ............ 864 Parametry zdalnych metod i wartoci zwracane ............................................................................................... 886 Rozdzia 11...... 926 Adnotacje kompilacji ........................................... 874 Aktywacja zdalnych obiektów ................................................ 874 Usugi sieciowe i JAX-WS .................... 916 Przykad — adnotacje obsugi zdarze ........................................................................................................................................................ 906 Przykad: dynamiczne tworzenie kodu w jzyku Java ................................................................................................................................................................................................................................................................................................................................................................... Obiekty rozproszone ................................................. 954 Wykorzystanie funkcji printf do formatowania liczb .............................................................................. 928 Metaadnotacje ........................................................................................................................................................................... 894 Przekierowanie wejcia i wyjcia .............................................................. 880 Stosowanie JAX-WS ..........................................................

.......................................................... 975 Obsuga bdów ..................................................... 968 Wywoywanie metod statycznych ................................................................................................................................................................ 973 Tablice ...................................... 990 Implementacja dostpu do rejestru za pomoc metod macierzystych ...................................................................... 973 Alternatywne sposoby wywoywania metod .......... 988 Rejestr systemu Windows .... 990 Skorowidz ........................... 988 Interfejs dostpu do rejestru na platformie Java .................................... 978 Interfejs programowy wywoa jzyka Java ......................................................................................................................................................................................................................................................................................................................................................... 967 Wywoywanie metod obiektów ................................................................................................................................................................................................. 983 Kompletny przykad: dostp do rejestru systemu Windows ...................Spis treci 9 Sygnatury .................. 966 Wywoywanie metod jzyka Java .................................................1005 ................................................... 972 Konstruktory ..............................

pliki. do którego moemy zapisa sekwencj bajtów. poniewa zespó Javy doczy specyfikacj interfejsów programowych zwizanych z przetwarzaniem wyrae regularnych do specyfikacji ulepszonej obsugi wejcia i wyjcia w Java SE 1. Q wyraenia regularne. W rozdziale przedstawiony jest równie mechanizm serializacji obiektów. ródem bd celem tych sekwencji bajtów mog by . które do obsugi wejcia i wyjcia wprowadzi pakiet java. Obiekt. Nie potrafilimy jednak znale dla niej lepszego miejsca w ksice. Q strumienie obiektów i serializacja. . nazywamy strumieniem wejcia. Q strumienie plików ZIP. Strumienie W jzyku Java obiekt.nio udostpniony w wersji Java SE 1. który umoliwia przechowywanie obiektów z tak atwoci. a take metody zapisywania do i wczytywania informacji z plików w formacie tekstowym i binarnym. W naszym wyborze nie bylimy zreszt osamotnieni. Q zarzdzanie plikami. i czsto wanie s. Q odczyt i zapis danych binarnych. W tym rozdziale omówimy metody obsugi plików i katalogów. Nastpnie omówimy szereg ulepsze. Q ulepszona obsuga wejcia i wyjcia. Rozdzia zakoczymy przedstawieniem problematyki wyrae regularnych. mimo e nie jest ona bezporednio zwizana ze strumieniami i plikami. z którego moemy odczyta sekwencj bajtów. z jak przechowujesz tekst i dane numeryczne.4. Q strumienie tekstowe.4. nazywamy strumieniem wyjcia.1 Strumienie i pliki W tym rozdziale: Q strumienie.

dopóki dany bajt nie zostanie wczytany lub zapisany.available().read(data). System. Jeeli aplikacja otworzy zbyt wiele strumieni. Poniewa strumienie binarne nie s zbyt wygodne do manipulacji danymi przechowywanymi w standardzie Unicode (przypomnijmy tutaj. wywoujc metod close. w którym wywoana metoda czeka na udostpnienie strumienia. e poniszy kod prawdopodobnie nigdy nie zostanie zablokowany: int bytesAvaible = System. if (bytesAvaible > 0) { byte[] dane = new byte[bytesAvaible]. Techniki zaawansowane ale take i poczenia sieciowe.in to predefiniowany obiekt klasy pochodnej od Input ´Stream. Klasy abstrakcyjne InputStream i Out ´putStream stanowi baz hierarchii klas opisujcych wejcie i wyjcie programów Java. a nawet bloki pamici. stworzono osobn hierarchi klas operujcych na znakach Unicode i dziedziczcych po klasach abstrakcyjnych Reader i Writer. do tej pory udostpnione wtkowi. nie zamykajc ich. zasoby systemu . opartych na dwubajtowych znakach Unicode. pozwalajcy pobiera informacje z klawiatury. Analogicznie. Metody te wywouj abstrakcyjna metod read.18 Java. } Gdy skoczymy odczytywa albo zapisywa dane do strumienia. Metody read i write potrafi zablokowa wtek. Klasa InputStream posiada równie nieabstrakcyjn metod pozwalajc pobra lub zignorowa tablic bajtów.in. nie przydaj si natomiast do znaków jednobajtowych. które w danym momencie odczyta . Dla przykadu. Klasy te s przystosowane do wykonywania operacji odczytu i zapisu. e Unicode opisuje kady znak za pomoc dwóch bajtów). tak wic podklasy musz przeadowa tylko t jedn metod. Dziki temu inne wtki mog wykorzysta czas procesora. w klasie FileInputStream metoda read czyta jeden bajt z pliku. Oznacza to. Oznacza to. dostarczajc w ten sposób uytecznej funkcjonalnoci.in. Java zawiesza wtek dokonujcy wywoania. Metoda ta uwalnia zasoby systemu operacyjnego. jeeli natrafi na koniec róda danych. e jeeli strumie nie moe natychmiastowo wczyta lub zapisa danego bajta (zazwyczaj z powodu powolnego poczenia sieciowego). Odczyt i zapis bajtów Klasa InputStream posiada metod abstrakcyjn: abstract int read() Metoda ta wczytuje jeden bajt i zwraca jego warto lub –1. Projektanci konkretnych klas strumieni wejcia przeadowuj t metod. zamykamy go. System. klasa OutputStream definiuje metod abstrakcyjn abstract void write(int b) która wysya jeden bajt do aktualnego wyjcia. Metoda available pozwala sprawdzi liczb bajtów.

0 Q abstract int read() pobiera jeden bajt i zwraca jego warto . zamknicie strumienia wyjcia powoduje oprónienie bufora uywanego przez ten strumie — wszystkie znaki. pod którym powinien zosta umieszczony pierwszy wczytany bajt. Metoda read czyta co najwyej b. to liczby. Mimo i klasy strumieni udostpniaj konkretne metody wykorzystujce funkcje read i write. którymi jestemy zwykle bardziej zainteresowani. aby mogy zosta zapisane w jednym wikszym pakiecie. Q int available() zwraca liczb bajtów dostpnych bez koniecznoci zablokowania wtku (pamitajmy. int off. jeeli natrafimy na koniec strumienia). Zwraca faktyczn liczb zignorowanych bajtów (która moe by mniejsza ni n. zwraca –1. eby programy musiay czyta i zapisywa sekwencje bajtów. w której zapisywane s dane. które pozwalaj operowa na danych w sposób bardziej dogodny anieli w przypadku pracy na poziomie pojedynczych bajtów. len maksymalna liczba wczytywanych bajtów. Q int read(byte[] b.io.length bajtów. Q void mark(int readlimit) ustawia znacznik na aktualnej pozycji strumienia wejcia (nie wszystkie strumienie obsuguj t moliwo ). Metoda read zwraca –1. Q int read(byte[] b) wczytuje dane do tablicy i zwraca liczb wczytanych bajtów. Java udostpnia wiele klas strumieni pochodzcych od podstawowych klas InputStream i OutputStream. ostatni pakiet bajtów moe nigdy nie dotrze do odbiorcy. off indeks tablicy b.Rozdzia 1. Jeeli ze strumienia zostao pobranych wicej ni readlimit bajtów. poniewa nieczsto si zdarza. Dane. strumie ma prawo usun znacznik. gdy natrafi na koniec strumienia. int len) wczytuje dane do tablicy bajtów. zostan natychmiast wysane. e zablokowanie oznacza. przy uyciu metody flush. Co wicej. przechowywane tymczasowo w buforze. Bufor moemy równie opróni wasnorcznie. . Q Strumienie i pliki 19 mog zosta naruszone. zwraca –1. a jeeli natrafi na koniec strumienia. programici Javy rzadko z nich korzystaj. e wykonanie aktualnego wtku zostaje wstrzymane). java. a jeeli natrafi na koniec strumienia. Zwraca liczb wczytanych bajtów. acuchy znaków i obiekty.InputStream 1. Jeeli nie zamkniemy strumienia. Q void close() zamyka strumie wejcia. Parametry: b tablica. Q long skip(long n) ignoruje n bajtów w strumieniu wejcia.

2). Techniki zaawansowane Q void reset() wraca do ostatniego znacznika. z której pobierane s dane. Na przykad. strumie nie zostanie zresetowany.OutputStream 1. klasy InputStream i OutputStream pozwalaj pobiera i wysya jedynie pojedyncze bajty oraz tablice bajtów. do obsugi tekstu Unicode uywamy klas pochodzcych od klas abstrakcyjnych Reader i Writer (patrz rysunek 1. java. off indeks tablicy b. Istniej osobne hierarchie klas przetwarzajcych bajty i znaki. Q void write(byte[] b) Q void write(byte[] b. Z drugiej strony. jeeli strumie obsuguje znaczniki. Parametry: b tablica.io. na przykad ZipInputStream i ZipOutputStream pozwalajce odczytywa i zapisywa dane w plikach skompresowanych w formacie ZIP. Q boolean markSupported() zwraca true. spod którego powinien zosta pobrany pierwszy zapisywany bajt. Q void close() oprónia i zamyka strumie wyjcia. o czym ju wspominalimy. Istnieje wiele poytecznych klas strumieni. Klasy te stanowi baz hierarchii pokazanej na rysunku 1. Podzielmy gatunki nalece do zoo klas strumieni zalenie od ich przeznaczenia. int len) zapisuj wszystkie bajty tablicy b lub pewien ich zakres.1 i 1. Do odczytu i zapisu liczb i acuchów znakowych uywamy ich podklas. który w zupenoci zadowala si jednym typem FILE*. Zoo pene strumieni W przeciwiestwie do jzyka C. Póniejsze wywoania read bd powtórnie czyta pobrane ju bajty.20 Java. Q void flush() oprónia strumie wyjcia. czyli wysya do odbiorcy wszystkie dane znajdujce si w buforze. Jeeli znacznik nie istnieje. Java posiada istne zoo ponad 60 (!) rónych typów strumieni (patrz rysunki 1. Jak ju o tym wspomnielimy.1.0 Q abstract void write(int n) zapisuje jeden bajt. . DataInputStream i DataOutputStream pozwalaj wczytywa i zapisywa wszystkie podstawowe typy Javy w postaci binarnej.2) Podstawowe metody klas Reader i Writer s podobne do tych nalecych do InputStream i OutputStream. int off. len liczba zapisywanych bajtów.

albo –1. ksiki Java 2.Rozdzia 1.1. jeeli natrafi na koniec pliku. Podstawy). Metoda write jest wywoywana dla podanego kodu znaku Unicode (wicej informacji na temat kodów Unicode znjadziesz w rozdziale 3. Q Strumienie i pliki 21 Rysunek 1. Hierarchia strumieni wejcia i wyjcia abstract int read() abstract void write(int b) Metoda read zwraca albo kod znaku Unicode (jako liczb z przedziau od 0 do 65535). .

Hierarchia klas Reader i Writer Poczwszy od Java SE 5. Techniki zaawansowane Rysunek 1. (Patrz punkt „Struktura bufora danych” na stronie 89). Readable i Appendable (patrz rysunek 1. Reprezentuje ona bufor w pamici lub map pliku w pamici.3). Pierwsze dwa z nich s wyjtkowo proste i zawieraj odpowiednio metody: void close() throws IOException i void flush() Klasy InputStream. wprowadzono cztery dodatkowe interfejsy: Closeable. Klasy OutputStream i Writer implementuj interfejs Flushable. Interfejs Readable ma tylko jedn metod int read(CharBuffer cb) Klasa CharBuffer ma metody do sekwencyjnego oraz swobodnego odczytu i zapisu. Interfejs Appendable ma dwie metody umolwiajce dopisywanie pojedynczego znaku bd sekwencji znaków: Appendable append(char c) Appendable append(CharSequence s) . Reader i Writer implementuj interfejs Closeable. OutputStream.2. Flushable.22 Java.0.

Moe wyrzuci wyjtek IOException.Flushable 5. CharBuffer. Interfejsy Closeable. java. Zwraca liczb wczytanych wartoci lub -1.Readable 5.io. Sporód klas strumieni jedynie klasa Writer implementuje interfejs Appendable.3. Flushable. Readable i Appendable Interfejs CharSequence opisuje podstawowe waciwoci sekwencji wartoci typu char.0 Q void flush() oprónia bufor danych zwizany z obiektem implementujcym interfejs Flushable.io.0 Q void close() zamyka obiekt implemetujcy interfejs Closeable. StringBuilder i StringBuffer.Appendable 5. java. java.Rozdzia 1.0 Q int read(CharBuffer cb) próbuje wczyta tyle wartoci typu char. ile moe pomieci cb. java. jeli obiekt Readable nie ma ju wartoci do pobrania.lang. Q Strumienie i pliki 23 Rysunek 1.lang. Interfejs ten implementuj klasy String.Closeable 5.0 Q Appendable append(char c) .

zwraca this. bardziej egzotycznych loka- . Oznacza to.read(). Q String toString() zwraca acuch znaków skadajcy si z kodów danej sekwencji.. czenie filtrów strumieni Klasy FileInputStream i FileOutputStream obsuguj strumienie wejcia i wyjcia przyporzdkowane okrelonemu plikowi na dysku. tak DataInput ´Stream nie posiada metody pozwalajcej czyta dane z pliku. W nastpnym podrozdziale przekonamy si. .24 Java. spróbuje odszuka w aktualnym katalogu plik o nazwie employee.getProperty("user. Ale tak jak FileInputStream nie posiada metod czytajcych typy liczbowe. moglibymy wczytywa typy liczbowe: DataInputStream din = . java.io uznaj relatywne cieki dostpu za rozpoczynajce si od aktualnego katalogu roboczego. Java korzysta ze sprytnego mechanizmu rozdzielajcego te dwa rodzaje funkcjonalnoci.dat.4 Q char charAt(int index) zwraca kod o podanym indeksie.dat"). byte b = (byte)fin. co to za katalog. Q CharSequence subSequence(int startIndex. W konstruktorze tych klas podajemy nazw pliku lub pen ciek dostpu do niego. powysze klasy obsuguj odczyt i zapis plików na poziomie pojedynczego bajta.1. powiniene wiedzie . double p = din. Moesz pobra t informacj poleceniem System. Poniewa wszystkie klasy w java. e z obiektu fin moemy czyta wycznie pojedyncze bajty oraz tablice bajtów.CharSequence 1. Techniki zaawansowane Q Appendable append(CharSequence cs) dopisuje podany kod znaku lub wszystkie kody podanej sekwencji do obiektu Appendable. Q int length() zwraca liczb kodów w sekwencji. . Na przykad FileInputStream fin = new FileInputStream("employee. int endIndex) zwraca sekwencj CharSequence zoon z kodów od startIndex do endIndex . Tak jak klasy abstrakcyjne InputStream i OutputStream.dir").readDouble(). Niektóre strumienie (takie jak FileInputStream i strumie wejcia zwracany przez metod openStream klasy URL) mog udostpnia bajty z plików i innych.lang. e korzystajc z DataInputStream.

a nastpnie przekaza go konstruktorowi DataInputStream.dat")))). DataInputStream din = DataInputStream (pbin = new PushbackInputStream (new BufferedInputStream (new FileInputStream("employee. PushbackInputStream pbin = new PushbackInputStream (new BufferedInputStream (new FileInputStream("employee. Czasami bdziemy zmuszeni utrzymywa czno ze strumieniami znajdujcymi si porodku acucha. musimy skorzysta z poniszej. aby sprawdzi . FileInputStream fin = new FileInputStream("employee. a take wczytywa liczby. czytajc dane. Róne funkcjonalnoci moemy dodawa poprzez zagniedanie filtrów.dat"). i umieci go z powrotem w strumieniu.1. W tym celu Java dostarcza klas PushbackInputStream.dat"))). Zwró my uwag. jeeli jego warto nie odpowiada naszym oczekiwaniom. musimy czsto podejrze nastpny bajt. if (b != '<') pbin.unread(b). Q Strumienie i pliki 25 lizacji.dat"))). powinien utworzy obiekt typu FileInputStream. Wró my do rysunku 1. Jeeli chcemy podejrze kolejne bajty. czy jego warto zgadza si z naszymi oczekiwaniami. Teraz moemy odczyta warto nastpnego bajta: int b = pbin. e DataInputStream znalaz si na ostatnim miejscu w acuchu konstruktorów. jak i do DataInputStream. monstrualnej sekwencji konstruktorów: DataInputStream din = new DataInputStream (new BufferedInputStream (new FileInputStream("employee. gdzie przedstawione s klasy FilterInputStream i FilterOutput ´Stream. Programista Javy musi poczy te dwa mechanizmy w jeden.readDouble(). potrzebujemy referencji zarówno do PushbackInputStream. Inne strumienie (takie jak DataInputStream i PrintWriter) potrafi tworzy z bajtów reprezentacj bardziej uytecznych typów danych. aby wczytywa liczby z pliku.read(). Ale wczytywanie i powtórne wstawianie to jedyne metody obsugiwane przez klas Push ´back-InputStream. który odczytuje kolejny bajt. Dla przykadu. Wobec tego kade wywoanie metody read oznacza odwoanie si do usug systemu operacyjnego. Jeli chcemy uzyska buforowany dostp do pliku. poniewa chcemy uywa metod klasy DataInputStream i chcemy. . double s = din.Rozdzia 1. Duo efektywniej bdzie da od systemu operacyjnego caych bloków danych i umieszcza je w buforze. Dla przykadu. Na przykad — domylnie strumienie nie s buforowane. Ich podklasy moemy wykorzysta do rozbudowy obsugi strumieni zwykych bajtów. DataInputStream din = new DataInputStream(fin). aby korzystay one z buforowanej metody read.

io. Jednak moliwo czenia klas filtrów i tworzenia w ten sposób naprawd uytecznych sekwencji strumieni daje nam niespotykan elastyczno . wic konieczno tworzenia ich kombinacji w jzyku Java wydaje si niepotrzebnym zawracaniem gowy. lub uywajc informacji zawartych w obiekcie file (klasa File zostanie omówiona pod koniec tego rozdziau). którego ciek dostpu zawiera parametr name. moemy wczytywa liczby ze skompresowanego pliku ZIP (patrz rysunek 1. uywajc pliku. java.io. ZipInputStream zin = new ZipInputStream(new FileInputStream("employee.zip")). w bibliotekach strumieni innych jzyków programowania takie udogodnienia jak buforowanie i kontrolowanie kolejnych bajtów s wykonywane automatycznie. Sekwencja filtrowanych strumieni Aby dowiedzie si wicej o obsudze formatu ZIP.4. zajrzyj do podrozdziau powiconego strumieniom plików ZIP na stronie 48. boolean append) Q FileOutputStream(File file) tworzy nowy obiekt typu . DataInputStream din = new DataInputStream(zin). korzystajc z poniszej sekwencji strumieni. którego cieka dostpu znajduje si w acuchu nazwa. Rysunek 1.FileInputStream 1.0 Q FileOutputStream(String name) Q FileOutputStream(String name.26 Java.FileOutputStream 1.0 Q FileInputStream(String name) tworzy nowy obiekt typu FileInputStream. uywajc pliku. Techniki zaawansowane Oczywicie. java.4). Q FileInputStream(File file) tworzy nowy obiekt typu FileInputStream. Na przykad. cieki dostpu s podawane wzgldem katalogu roboczego skonfigurowanego podczas uruchamiania maszyny wirtualnej Java.

Strumie buforowany wczytuje znaki ze strumienia danych. moemy wybiera pomidzy formatem binarnym i tekstowym. w pliku pojawi si sekwencja bajtów 00 00 04 D2 (w notacji szesnastkowej).io. o domylnym rozmiarze bufora. Dla przykadu: jeeli liczba cakowita 1234 zostanie zapisana w postaci binarnej. W poniszym podrozdziale skoncentrujemy si na tekstowym wejciu-wyjciu.PushbackInputStream 1. int size) tworz strumie umoliwiajcy podgld kolejnego bajta wraz z buforem o podanym rozmiarze. Strumie umieszcza w buforze znaki. W przeciwnym razie istniejcy plik o tej samej nazwie zostanie skasowany. W formacie tekstowym liczba ta zostanie zapisana jako acuch "1234". Mimo i zapis danych w postaci binarnej jest szybki i efektywny. Q PushbackInputStream(InputStream we. dane doczane s na kocu pliku. dane s przesyane odbiorcy. a istniejcy plik o tej samej nazwie nie zostanie skasowany. dziki czemu przy nastpnym wywoaniu read zostanie on ponownie odczytany. java. java. Q Q Strumienie i pliki 27 FileOutputStream(File file. . Q void unread(int b) wstawia bajt z powrotem do strumienia.io.Rozdzia 1. boolean append) tworzy nowy strumie wyjciowy pliku okrelonego za pomoc acucha file lub obiektu file (klasa File zostanie omówiona pod koniec tego rozdziau). które powinny zosta zapisane. to uzyskany wynik jest kompletnie nieczytelny dla ludzi. Gdy bufor zapeni si lub gdy strumie zostanie opróniony.io. system przele do niego nowy blok danych. Parametry: b zwracany bajt Strumienie tekstowe Zapisujc dane.0 Q BufferedInputStream(InputStream in) tworzy nowy obiekt typu BufferedInputStream.0 Q PushbackInputStream(InputStream in) tworzy strumie sprawdzajcy warto nastpnego w kolejce bajta. java. Gdy bufor zostanie opróniony. nie wymuszajc za kadym razem dostpu do urzdzenia. Jeeli parametr append ma warto true.0 Q BufferedOutputStream(OutputStream out) tworzy nowy obiekt typu Buffered-OutputStream. nie wymuszajc za kadym razem dostpu do urzdzenia. o domylnym rozmiarze bufora.BufferedOutputStream 1.BufferedInputStream 1.

Do zapisywania danych za pomoc obiektu klasy PrintWriter uywamy tych samych metod print i println. short. zawierajcy bajty (reprezentujce znaki za pomoc okrelonego kodowania). stosujc odpowiednie kodowanie znaków. double).out. Moemy wykorzystywa je do zapisu liczb (int.in). Poniewa obiekty tekstowego wejcia i wyjcia s tak czsto doczane do plików. musimy uwzgldni sposób kodowania znaków. . Wicej informacji na temat kodowania znaków znajdziesz w punkcie „Zbiory znaków” na stronie 35. Java dostarcza w tym celu dwie wygodne klasy: FileReader i FileWriter. znaków. stanowi odpowiednik instrukcji PrintWriter out = new PrintWriter(new FileWriter("employee. Jednake obecnie wikszo rodowisk. W przypadku kodowania UTF-16 acuch "1234" zostanie zakodowany jako 00 31 00 32 00 33 00 34 (w notacji szesnastkowej). wartoci logicznych. jest równoznaczna z FileWriter out = new FileWriter(new FileOutputStream("output. Natomiast klasa InputStreamReader zamienia strumie wejcia. Na przykad instrukcja FileWriter out = new FileWriter("output.txt")). w których uruchamiamy programy w jzyku Java. Obiekt wejcia korzysta z domylnego kodowania lokalnego systemu. Techniki zaawansowane Zapisujc acuchy znakowe. nasz przykadowy acuch zostanie zapisany jako 31 32 33 34. Dla wygody programistów ma ona konstruktor umoliwiajcy poczenie obiektu klasy PrintWriter z FileWriter. acuchów znakowych i obiektów. Klasa OutputStreamWriter zamienia strumie znaków Unicode na strumie bajtów. podajc jego nazw w konstruktorze InputStream ´Reader. najczciej stosowanym w USA i Europie Zachodniej.txt"). Zatem instrukcja PrintWriter out = new PrintWriter("employee. Zapisywanie tekstu W celu zapisania tekstu korzystamy z klasy PrintWriter. na przykad: InputStreamReader in = new InputStreamReader(new FileInputStream("kremlin. na przykad ISO 8859-1 Moemy wybra inny sposób kodowania. których uywalimy dotd z obiektem System. uywa swojego wasnego formatu tekstu. ´"ISO8859_5"). Poniej przedstawiamy sposób utworzenia obiektu wejcia. W kodzie ISO 8859-1. long. wczytujcego znaki z konsoli i automatycznie konwertujcego je na Unicode.28 Java. InputStreamReader in = new InputStreamReader(System. bez bajtów o wartoci zero.txt"). float. Dysponuje ona metodami umoliwiajcymi zapis acuchów i liczb w formacie tekstowym. na obiekt udostpniajcy znaki Unicode.txt").dat").

Weterani Javy prawdopodobnie zastanawiaj si. Ale obecna klasa PrintStream konwertuje znaki Unicode na schemat kodowania lokalnego systemu w ten sam sposób. ale w przeciwiestwie do PrintWriter pozwalaj wysya bajty za pomoc metod write(int) i write(byte[]). W jzyku Java 1.0 do strumienia out. Nastpnie znaki zostan skonwertowane na bajty i zapisane w pliku employee. e metody println bd oprónia bufor (domylnie: false).print(' '). out. po prostu opuszczajc górny bajt.separator"). czy ze strumieniem jest wszystko w porzdku. Znak koca wiersza moemy pobra . Takie rozwizanie nie pozwalao na przenoszenie kodu na inne platformy i w jzyku Java 1.out. "\n" w Unix). nie obiektami odczytu i zapisu. Rezultatem jego wykonania bdzie wysanie napisu Harry Hacker 75000.getProperty("line.in. boolean autoFlush) tworzy nowy obiekt klasy PrintWriter. boolean autoFlush: PrintWriter out = new PrintWriter(new FileWriter("employee. Aby sprawdzi . stosujc wywoanie System. out.PrintWriter 1.err wci s strumieniami.0 klasa PrintStream obcinaa znaki Unicode do znaków ASCII. Q Strumienie i pliki 29 Spójrzmy na poniszy kod: String name = "Harry Hacker". Gdy uywamy metod print i println. java.out i System. w chwili wywoania metody println wszystkie znaki w buforze zostan wysane do odbiorcy (obiekty PrintWriter zawsze s buforowane).println(salary).txt.1 Q PrintWriter(Writer out) Q PrintWriter(Writer out. Automatyczne oprónianie moemy wcza i wycza przy uyciu konstruktora PrintWriter(Writer out. double salary = 75000. // automatyczne oprónianie Metody print nie wyrzucaj wyjtków.1 zostao zastpione przez koncepcj obiektów odczytu i zapisu. Ze wzgldu na konieczno zachowania zgodnoci System. autoFlush true oznacza. Domylnie automatyczne oprónianie jest wyczone. Parametry: out obiekt zapisu tekstu. co si stao z klas PrintStream i obiektem System. odpowiedni dla danego systemu operacyjnego ("\r\n" w systemie Windows.Rozdzia 1. Jeeli obiekt zapisu znajduje si w trybie automatycznego opróniania.print(name). wywoujemy metod checkError.io. co klasa PrintWriter. true). System. out. Metoda println automatycznie dodaje znak koca wiersza.txt". obiekty PrintStream dziaaj tak samo jak obiekty PrintWriter. .

Q void print(Object obj) drukuje acuch zwracany przez metod toString danego obiektu. boolean autoFlush) tworzy nowy obiekt klasy PrintWriter na podstawie istniejcego obiektu typu OutputStream... jeeli wystpi bd formatowania lub zapisu. Q void print(int i) Q void print(long l) Q void print(float f) Q void print(double d) Q void print(boolean b) drukuje podan warto w formacie tekstowym. Q boolean checkError() zwraca true. Q void println(String p) drukuje acuch zakoczony znakiem koca wiersza. Q void printf(String format. Podstawy. oprónia bufor strumienia. poprzez utworzenie poredniczcego obiektu klasy OutputStreamWriter. Object. Parametry: obj drukowany obiekt. args) drukuje podane wartoci wedug acucha formatujcego. Jeeli w strumieniu danych wystpi bd. Specyfikacj acucha formatujcego znajdziesz w rozdziale 3. Techniki zaawansowane Q PrintWriter(OutputStream out) Q PrintWriter(OutputStream out. Jeeli automatyczne oprónianie jest wczone. Q PrintWriter(String filename) Q PrintWriter(File file) tworzy nowy obiekt klasy PrintWriter zapisujcy dane do pliku poprzez utworzenie poredniczcego obiektu klasy FileWriter. tainted) i wszystkie nastpne wywoania metody checkError bd zwraca true. Q void print(String p) drukuje acuch Unicode. ksiki Java 2. strumie zostanie uznany za niepewny (ang.30 Java. . Q void print(char[] p) drukuje tablic znaków Unicode. Q void print(char c) drukuje znak Unicode.

albo te. przed wprowadzeniem Java SE 5. Aby j wykorzysta . uywamy klasy DataOutputStream. while ((line = in. e: Q aby zapisa dane w formacie binarnym. Typowa ptla pobierania danych wyglda wic nastpujco: String line. e istnieje równie klasa analogiczna do DataInput ´Stream.Rozdzia 1.txt")).readLine()) != null) { operacje na danych line } Jednak klasa BufferedReader nie udostpnia metod odczytu danych liczbowych. jeli znak | znajdzie si w jednym z zapisywanych przez nas acuchów? Oto przykadowy zbiór danych obiektów: Harry Hacker|35500|1989|10|1 Carl Cracker|75000|1987|12|15 Tony Tester|38000|1990|3|15 Zapis tych rekordów jest prosty. Najbliszym odpowiednikiem jest w tym przypadku klasa Scanner. któr dodamy do klasy Employee. Podstawy. \n. Dane kadego obiektu zostan zapisane w osobnym wierszu. Po prostu zapisujemy wszystkie pola skadowe. Jeeli dalsze wczytywanie nie jest moliwe. po ostatnim polu. Ma ona metod readLine pozwalajc pobra wiersz tekstu. Q aby zapisa dane w formacie tekstowym. Dlatego do odczytu danych sugerujemy zastosowanie klasy Scanner. Jako separatora uywamy pionowej kreski (|) (innym popularnym separatorem jest dwukropek (:). musimy najpierw poczy obiekt typu BufferedReader ze ródem wejcia. metoda readLine zwraca null.0 mona byo uy w tym celu jedynie klasy BufferedReader. uywamy klasy PrintWriter. Wartoci pól skadowych zostan oddzielone od siebie separatorami. za kadym z nich stawiajc |. Zapis obiektów w formacie tekstowym W tym podrozdziale przeanalizujemy dziaanie przykadowego programu. która pozwoli nam czyta dane w formacie tekstowym. uywamy klasy PrintWriter. Poniewa korzystamy z pliku tekstowego. Na tej podstawie mona si domyla . co bdzie. Niestety. zabawa polega na tym. taki wybór stawia przed nami pytanie. który bdzie zapisywa tablic obiektów typu Employee w pliku tekstowym. . e kady programista uywa innego separatora). BufferedReader in = new BufferedReader(new FileReader("employee. Naturalnie. Operacje te wykona ponisza metoda writeData. któr wykorzystywalimy intensywnie w ksice Java 2. Q Strumienie i pliki 31 Wczytywanie tekstu Wiemy ju.

println(name + "|" + salary + "|" + calendar. } Wywoanie metody nextInt wczytuje rozmiar tablicy.getTime().parseDouble(tokens[1]). Techniki zaawansowane public void writeData(PrintWriter out) throws IOException { GregorianCalendar calendar = new GregorianCalendar(). GregorianCalendar calendar = new GregorianCalendar(y. Poniewa pionowa kreska ma specjalne znaczenie w wyraeniach regularnych.get(Calendar. Ten z kolei musimy poprzedzi jeszcze jednym znakiem \ — w efekcie uzyskujc wyraenie postaci "\\|".nextInt(). to musimy poprzedzi j znakiem \.32 Java. aby metoda readData moga uzyska kolejny wiersz. Metoda statyczna void writeData(Employee[] e. int m = Integer. in.parseInt(tokens[4]). for (int i = 0. employees[i].setTime(hireDay). Wymaga to zastosowania pewnej sztuczki: int n = in. int d = Integer.MONTH) + 1) + "|" + calendar. Wyraenie regularne omówimy bardziej szczegóowo pod koniec biecego rozdziau. Do wczytania wierszy uyjemy obiektu klasy Scanner.split pozwoli nam wyodrbni poszczególne tokeny. Metoda statyczna Employee[] readData(BufferedReader in) najpierw wczytuje rozmiar tablicy.get(Calendar.YEAR) + "|" + (calendar.split("\\|"). out. a nastpnie kady z rekordów. .1. a nastpnie kady z rekordów. PrintWriter out) najpierw zapisuje rozmiar tablicy. i++) { employees[i] = new Employee(). Kompletny program zosta przedstawiony na listingu 1. // konsumuje znak nowego wiersza Employee[] employees = new Employee[n]. } Parametrem metody split jest wyraenie regularne opisujce separator.DAY_OF_MONTH)). d). Musimy zatem go pobra (wywoujc metod nextLine). a metoda String.readData(in). hireDay = calendar.parseInt(tokens[2]). public void readData(Scanner in) { String line = in. i < n. wczytujemy po jednym wierszu tekstu i rozdzielamy pola skadowe. } Aby odczyta te dane. int y = Integer. ale nie nastpujcy po nim znak nowego wiersza.1. String[] tokens = line. m .nextLine().nextLine(). kalendarz. salary = Double.parseInt(tokens[3]).get(Calendar. name = tokens[0].

println(employees.*.close(). PrintWriter out) throws ´IOException { // zapisuje liczb obiektów out. 15).java import java.1.out. Employee[] newStaff = readData(in). out.io. 12. // wywietla wszystkie wczytane rekordy for (Employee e : newStaff) System. 1989.12 2007-06-22 * @author Cay Horstmann */ public class TextFileTest { public static void main(String[] args) { Employee[] staff = new Employee[3].*. try { // zapisuje wszystkie rekordy pracowników w pliku employee. 50000. } catch (IOException exception) { exception. // wczytuje wszystkie rekordy do nowej tablicy Scanner in = new Scanner(new FileReader("employee. staff[2] = new Employee("Tony Tester". 1).dat"). 40000. 10. TextFileTest.close(). staff[1] = new Employee("Harry Hacker". writeData(staff. Q Strumienie i pliki Listing 1. } 33 . import java. /** * @version 1. 75000. out).util.println(e).Rozdzia 1.printStackTrace().dat")). 1990. staff[0] = new Employee("Carl Cracker".dat PrintWriter out = new PrintWriter("employee. 1987. } } /** * Zapisuje dane wszystkich obiektów klasy Employee * umieszczonych w tablicy * do obiektu klasy PrintWriter * @param employees tablica obiektów klasy Employee * @param out obiekt klasy PrintWriter */ private static void writeData(Employee[] employees. 3. in.length). for (Employee e : employees) e.writeData(out). 15).

nextInt().nextLine(). } public String getName() { return name. } public Date getHireDay() { return hireDay. hireDay = calendar. // pobiera znak nowego wiersza Employee[] employees = new Employee[n]. Techniki zaawansowane /** * Wczytuje tablic obiektów klasy Employee * @param in obiekt klasy Scanner * @return tablica obiektów klasy Employee */ private static Employee[] readData(Scanner in) { // pobiera rozmiar tablicy int n = in. i++) { employees[i] = new Employee(). int year. } public String toString() . double s.readData(in). for (int i = 0. int day) { name = n. } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100. in. employees[i]. day). month . salary = s. } return employees. GregorianCalendar calendar = new GregorianCalendar(year.1.34 Java. } } class Employee { public Employee() { } public Employee(String n. } public double getSalary() { return salary. int month. salary += raise.getTime(). i < n.

hireDay=" + hireDay + "]". } /** * Wczytuje dane obiektu klasy Employee * @param in obiekt klasy Scanner */ public void readData(Scanner in) { String line = in. Sytuacja zmienia si z wprowadzeniem pakietu java. GregorianCalendar calendar = new GregorianCalendar(y. salary = Double. out. w którym . który unifikuje konwersje zbiorów znaków.println(name + "|" + salary + "|" + calendar.4. hireDay = calendar. private Date hireDay. m .parseDouble(tokens[1]). Zbiór znaków stanowi odwzorowanie pomidzy dwubajtowymi kodami Unicode i sekwencjami bajtów stosowanymi w lokalnych kodowaniach znaków. Q Strumienie i pliki 35 { return getClass().salary=" + salary + ´".parseInt(tokens[3]).nio w Java SE 1. int y = Integer. int d = Integer. } /** * Zapisuje dane obiektu klasy Employee * do obiektu klasy PrintWriter * @param out obiekt klasy PrintWriter */ public void writeData(PrintWriter out) { GregorianCalendar calendar = new GregorianCalendar(). calendar.parseInt(tokens[4]). Jednym z najpopularniejszych kodowa znaków jest ISO-8859-1.parseInt(tokens[2]). które koduje za pomoc jednego bajta pierwszych 256 znaków z zestawu Unicode.get(Calendar.getTime(). udostpniajc klas Charset (zwró my uwag na ma liter s w nazwie klasy). Coraz wiksze znaczenie zyskuje równie ISO08859-15.nextLine(). name = tokens[0].get(Calendar.DAY_OF_MONTH)). private double salary.split("\\|").getName() + "[name=" + name + ". } private String name. String[] tokens = line.Rozdzia 1.1. } Zbiory znaków We wczeniejszych edycjach platformy Java problem znaków narodowych obsugiwany by w mao systematyczny sposób.get(Calendar.MONTH) + 1) + "|" + ´calendar. int m = Integer.YEAR) + "|" + (calendar.setTime(hireDay). d).

Nazwy te róni si nieco od nazw stosowanych w poprzednich wersjach. a przede wszystkim zamiast znaku waluty midzynarodowej ¤ umieszczono symbol euro (€) o kodzie 0xA4.out.println(name). Innymi przykadami kodowa znaków s kodowania o zmiennej liczbie bajtów stosowane dla jzyków japoskiego i chiskiego.aliases(). for (String alias : aliases) System. for (String name : charsets. które zbiory znaków s dostpne dla konkretnej implementacji.net/charsets/ iso8859. Charset> charsets = Charset. Techniki zaawansowane zastpiono cz mniej przydatnych znaków kodu ISO-8859-1 akcentowanymi znakami jzyka francuskiego i fiskiego. wywoujemy metod statyczn availableCharsets. Poniej przedstawiamy kod umoliwiajcy przegldanie synonimów: Set<String> aliases = cset.forName("ISO-8859-1").out.3 i wczeniejszych wersjach.keySet()) System.36 Java.iana. Na przykad dla ISO-8859-1 istniej nastpujce synonimy: ISO8859-1 ISO_8859_1 ISO8859_1 ISO_8859-1 ISO_8859-1:1987 8859_1 latin1 l1 csISOLatin1 iso-ir-100 cp819 IBM819 IBM-819 819 Metoda aliases zwraca obiekt klasy Set zawierajcy synonimy. Poniszy kod pozwala pozna nazwy wszystkich dostpnych zbiorów znaków: Map<String. . której podajemy oficjaln nazw zbioru znaków lub jeden z jej synonimów: Charset cset = Charset.org/assignments/character-sets). Due i mae litery nie s rozróniane w nazwach zbiorów znaków. Aby dowiedzie si. Opis kodowania ISO 8859 znajdziesz na stronie http://aspell.html. Na przykad „oficjaln” nazw ISO-8859-1 jest teraz "ISO-8859-1" zamiast "ISO8859_1" preferowan w Java SE 1. Ze wgldu na konieczno zachowania zgodnoci z innymi konwencjami nazw nazwa kadego zbioru znaków moe mie wiele synonimów. Klasa Charset uywa nazw zbiorów znaków zgodnie ze standardem okrelonym przez IANA Character Set Registry (http://www.availableCharsets(). wywoujc metod statyczn forName.println(alias). Obiekt klasy Charset uzyskujemy.

wschodnioeuropejski windows-1251 Cp1251 Windows Cyrillic windows-1252 Cp1252 Windows. alfabet Latin 7 ISO8859-15 ISO8859_15 ISO 8859-15. porzdek bajtów od najmodszego Tabela 1. alfabet Latin 9 windows-1250 Cp1250 Windows. Podstawowe kodowania znaków Standardowa nazwa obiektu Charset Nazwa tradycyjna Opis ISO8859-2 ISO8859_2 ISO 8859-2.2.3 s instalowane tylko w przypadku systemów operacyjnych uywajcych jzyków innych ni europejskie. W tabeli 1. alfabet Latin 2 ISO8859-4 ISO8859_4 ISO 8859-4. alfabet Latin 4 ISO8859-5 ISO8859_5 ISO 8859-5. alfabet Latin/Greek ISO8859-9 ISO8859_9 ISO 8859-9. Tabela 1. alfabet Latin 1 UTF-8 UTF8 8-bitowy Unicode Transformation Format UTF-16 UTF-16 16-bitowy Unicode Transformation Format. batycki . Latin 1 windows-1253 Cp1253 Windows. porzdek bajtów okrelony przez opcjonalny znacznik UTF-16BE UnicodeBigUnmarked 16-bitowy Unicode Transformation Format. porzdek bajtów od najstarszego UTF-16LE UnicodeLittleUnmarked 16-bitowy Unicode Transformation Format.Rozdzia 1.2 wymienione zostay schematy kodowania instalowane domylnie przez pakiet JDK. Q Strumienie i pliki 37 W tabeli 1. które musi obsugiwa kada implementacja platformy Java. alfabet Latin 5 ISO8859-13 ISO8859_13 ISO 8859-13. turecki windows-1257 Cp1257 Windows.1 zostay przedstawione wszystkie kodowania znaków.1. grecki windows-1254 Cp1254 Windows. Kodowania znaków wymagane na platformie Java Standardowa nazwa obiektu Charset Nazwa tradycyjna Opis US-ASCII ASCII American Standard Code for Information Exchange ISO-8859-1 ISO8859_1 ISO 8859-1. Zbiory znaków przedstawione w tabeli 1. alfabet Latin/Cyrillic ISO8859-7 ISO8859_7 ISO 8859-7.

japoski ISO-2022-KR ISO2022KR ISO 2022 KR. tradycyjny chiski Lokalne schematy kodowania nie mog oczywicie reprezentowa wszystkich znaków Unicode. tajski windows-1255 Cp1255 Windows. 0208 w postaci ISO 2022. Techniki zaawansowane Tabela 1. kodowanie EUC. uproszczony chiski ISCII91 ISCII91 ISCII91. arabski windows-1258 Cp1258 Windows. koreaski GB18030 GB18030 uproszczony chiski. to zostaje przeksztacony na znak ?. uproszczony chiski x-windows-949 MS949 Windows. Dysponujc zbiorem znaków. Latin 3 ISO8859-6 ISO8859_6 ISO 8859-6. moemy uy go do konwersji acuchów Unicode i sekwencji bajtów.38 Java.3. Rozszerzone kodowania znaków Standardowa nazwa obiektu Charset Nazwa tradycyjna Opis Big5 Big5 Big5. alfabet aciski/hebrajski Shift_JIS SJIS Shift_JIS. kodowanie EUC. tradycyjny chiski x-MS950-HKSCS MS950_HKSCS Windows. Jeli znak nie jest reprezentowany. japoski EUC-KR EUC_KR KS C 5601. wietnamski windows-3lj MS392 Windows. tradycyjny chiski z rozszerzeniami Hongkong EUC-JP EUC_JP JIS X 0201. kodowanie EUC. uproszczony chiski x-EUC-JP-LINUX EUC_JP_LINUX JIS X 0201. japoski x-EUC-TW EUC_TW CNS11643 (Plane 1-3). kodowanie EUC. koreaski ISO8859-3 ISO8859_3 ISO 8859-3. standard PRC GBK GBK GBK. 0208. hebrajski windows-1256 Cp1256 Windows. alfabet aciski/arabski ISO8859-8 ISO8859_8 ISO 8859-8. tradycyjny chiski z rozszerzeniami Hongkong x-mswin-936 MS936 Windows. japoski x-EUC-CN EUC_CN GB2313. indu ISO-2022-JP ISO2022JP JIS X 0201. tradycyjny chiski Big5-HKSCS Big5_HKSCS Big5. Oto przykad kodowania acucha Unicode: . 0208. koreaski x-windows-950 MS950 Windows. japoski TIS-620 TIS620 TIS620. kodowanie EUC. 0212.

decode(bbuf). java.nio. int offset. Nierozpoznane bajty s zamieniane na specjalny znak Unicode ('\uFFFD'). byte[] bytes = buffer. której kluczami s nazwy zbiorów znaków.CharBuffer Q char[] array() zwraca tablic kodów.nio.encode(str). . Q ByteBuffer encode(String str) dokonuje konwersji podanego acucha na sekwencj bajtów. Wykorzystamy metod statyczn wrap tablicy ByteBuffer. potrzebny bdzie bufor. ByteBuffer bbuf = ByteBuffer. length).charset.Charset 1. aby uzyska acuch znaków. a wartociami same zbiory. Q static ByteBuffer wrap(byte[] bytes) Q static ByteBuffer wrap(byte[] bytes. . Q Strumienie i pliki 39 String str = . String str = cbuf.wrap(bytes. któr zarzdza ten bufor. ByteBuffer buffer = cset. który zarzdza podan tablic bajtów lub jej okrelonym zakresem. Q CharBuffer decode(ByteBuffer buffer) dokonuje konwersji sekwencji bajtów. Zwraca map. aby przeksztaci tablic bajtów w bufor. java. byte[] bytes = . . któr zarzdza ten bufor..4 Q static SortedMap availableCharsets() pobiera wszystkie zbiory znaków dostpne dla maszyny wirtualnej. CharBuffer cbuf = cset. Q char charAt(int index) zwraca kod o podanym indeksie. Wystarczy wywoa jego metod toString. Q static Charset forName(String name) zwraca zbiór znaków o podanej nazwie. java.toString().nio. Q Set aliases() zwraca zbiór synonimów nazwy danego zbioru znaków. .ByteBuffer 1.. W wyniku dziaania metody decode otrzymujemy obiekt klasy CharBuffer. int length) zwraca bufor.4 Q byte[] array() zwraca tablic bajtów.Rozdzia 1. offset.array(). Natomiast aby dokona konwersji w kiedunku przeciwnym. .

znaki acucha s najpierw reprezentowane w kodzie UTF-16 (patrz tabela 1.5).40 Java. Zamiast po prostu zastosowa od razu standardowe kodowanie UTF-8 (przedstawione w tabeli 1. e pracujesz z czterobajtow wartoci. W jzyku Java zawsze stosowany jest pierwszy sposób. least significant byte. liczby cakowite i zmiennoprzecinkowe mog by przechowywane w pamici na dwa róne sposoby. Odczyt i zapis danych binarnych Aby zapisa liczb. a writeDouble zawsze zapisuje liczby double jako wartoci omiobajtowe. a dopiero potem przekodowywane na UTF-8. e pierwszym z czterech bajtów pamici bdzie bajt najbardziej znaczcy (ang. warto logiczn lub acuch. Wynik takiego kodowania róni si dla znaków o kodach wikszych od 0xFFFF. Dziki temu pliki danych programów w jzyku Java s niezalene od platformy. . Kodowanie takie stosuje si dla zachowania zgodnoci z maszynami wirtualnymi powstaymi. niezalenie od procesora. e bdzie to bajt najmodszy (ang.4). gdy Unicode zadowala si tylko 16 bitami. ale poniewa wymagana ilo bajtów jest taka sama dla kadej wartoci danego typu. Moe ona zosta przechowana w ten sposób. niezalenie od liczby jej cyfr. Rezultat tych dziaa nie jest czytelny dla czowieka. czyli 4D2 w zapisie szesnastkowym (1234 = 4×256+13×16+2). korzystamy z jednej z poniszych metod interfejsu DataOutput: writeChars writeByte writeInt writeShort writeLong writeFloat writeDouble writeChar writeBoolean writeUTF Na przykad. Zaómy. na przykad 1234. Albo w taki sposób. Unicode Text Format). to wczytanie ich z powrotem bdzie szybsze ni parsowanie zapisu tekstowego. który tworz kody zarzdzane przez ten bufor. Techniki zaawansowane Q String toString() zwraca acuch. Poniewa opisana modyfikacja kodowania UTF-8 stosowana jest wycznie na platformie Java. to metody writeUTF powinnimy uywa tylko do zapisu acuchów przetwarzanych przez programy wykonywane przez maszyn wirtualn Java. uywajc zmodyfikowanej wersji 8-bitowego kodu UTF (ang. Metoda writeUTF zapisuje acuchy. writeInt zawsze zapisuje liczb integer jako warto czterobajtow. MSB): 00 00 04 D2. znak. tak jak int. LSB): D2 04 00 00. W pozostaych przypadkach naley uywa metody writeChars. a drugi przez procesory Pentium. Pierwszy sposób stosowany jest przez maszyny SPARC. Moe to powodowa problemy z przenoszeniem nawet najprostszych plików danych pomidzy rónymi platformami. Zalenie od platformy uytkownika. most significant byte.

Q Strumienie i pliki 41 Tabela 1. aby zapisa dane binarne.4.. uywamy klasy DataOutputStream implementujcej interfejs DataOutput: DataOutputStream out = new DataOutputStream(new FileOutputStream("employee. Aby odczyta dane.10FFFF 110110b19b18b17b16a15a14a13a12a11a10 110111a9a8 a7a65a4a3a2a1a0 gdzie b19b18b17b16 = a20a19a18a17a16 .txt).dat")).Rozdzia 1..10FFFF 11110a20a19a18 10a17a16a15a14a13a12 10a11a10a9a8a7a6 10a5a4a3a2a1a0 Tabela 1.7F 0a6a5a4a3a2a1a0 80.. takim jak na przykad obiekt klasy FileInputStream: DataInputStream in = new DataInputStream(new FileInputStream("employee...FFFF a15a14a13a12a11a10a9a8 a7a6a5a4a3a2a1a0 10000..1 Definicje kodów UTF-8 i UTF-16 znajdziesz w dokumentach...txt) i RFC 2781 (http://ietf. Podobnie. korzystamy z poniszych metod interfejsu DataInput: readInt readShort readLong readFloat readDouble readChar readBoolean readUTF Klasa DataInputStream implementuje interfejs DataInput.dat")).. java.7FF 110a10a9a8a7a6 10a5a4a3a2a1a0 800.0 Q boolean readBoolean() Q byte readByte() Q char readChar() Q double readDouble() Q float readFloat() . czymy obiekt klasy DataInputStream ze ródem bajtów.io.org/rfc/rfc2781. Aby odczyta dane binarne z pliku. odpowiednio: RFC 2279 (http://ietf. Kodowanie UTF-8 Zakres znaków Kodowanie 0. Kodowanie UTF-16 Zakres znaków Kodowanie 0.org/rfc/rfc2279..DataInput 1..5.FFFF 1110a15a14a13a12 10a11a10a9a8a7a6 10a5a4a3a2a1a0 10000..

. Q String readUTF() wczytuje acuch znaków zapisanych w zmodyfikowanym formacie UTF-8. Q void writeChars(String s) zapisuje wszystkie znaki podanego acucha. dopóki wszystkie bajty nie zostan zignorowane. Q int skipBytes(int n) ignoruje n bajtów. dopóki wszystkie bajty nie zostan wczytane. blokujc wtek. Techniki zaawansowane Q int readInt() Q long readLong() Q short readShort() wczytuje warto okrelonego typu. len maksymalna ilo odczytanych bajtów.0 Q void writeBoolean(boolean b) Q void writeByte(int b) Q void writeChar(char c) Q void writeDouble(double d) Q void writeFloat(float f) Q void writeInt(int i) Q void writeLong(long l) Q void writeShort(short s) zapisuj warto okrelonego typu. off indeks pierwszego bajta. do którego zapisywane s dane. java. blokujc wtek. Q void readFully(byte[] b) wczytuje bajty do tablicy b. Q void writeUTF(String s) zapisuje acuch znaków w zmodyfikowanym formacie UTF-8. dopóki wszystkie bajty nie zostan wczytane.DataOutput 1. int off. Parametry: b bufor. int len) wczytuje bajty do tablicy b. Parametry: b bufor. Q void readFully(byte[] b.42 Java. blokujc wtek. do którego zapisywane s dane. Parametry: n liczba ignorowanych bajtów.io.

co uatwi nam ich wczytywanie. a nastpnie moemy ju wczyta rekord.1) * RECORD_SIZE). Do plików dyskowych moemy uzyska swobodny dostp. które omówilimy w poprzednim podrozdziale. Q Strumienie i pliki 43 Strumienie plików o swobodnym dostpie Strumie RandomAccessFile pozwala pobra lub zapisa dane w dowolnym miejscu pliku. który przechowuje rekordy pracowników w pliku o swobodnym dostpie. który zostanie wczytany lub zapisany. dzielc liczb bajtów przez rozmiar rekordu. uywajc jako drugiego argumentu konstruktora acucha "r" (odczyt) lub "rw" (odczyt i zapis). na którym naley ustawi ten wskanik. np. Aby czyta z pliku o swobodnym dostpie. Plik o swobodnym dostpie posiada wska nik pliku. e. na który wskazuje. inaczej ni w przypadku strumieni danych pochodzcych z sieci. Jeli zmodyfikujemy rekord i bdziemy chcieli zapisa go w tym samym miejscu pliku.dat". Musimy zatem wyznaczy bajt. long nbytes = in. Klasa RandomAccessFile implementuje zarówno interfejs DataInput. "r"). readInt/writeInt lub readChar/writeChar. Metoda getFilePointer zwraca aktualne pooenie wskanika pliku. Stworzymy zatem dwie metody pomocnicze pozwalajce zapisywa i wczytywa acuchy o ustalonym rozmiarze.length(). Employee e = new Employee(). // dugo w bajtach int nrecords = (int) (nbytes / RECORD_SIZE).writeData(out). okrelajc numer bajta. to dopenia acuch wartociami zerowymi). long n = 3. uywamy metody length.readData(in). musimy pamita . Argumentem metody seek jest liczba typu long z przedziau od 0 do dugoci pliku w bajtach. Aby okreli cakowit liczb bajtów w pliku. Metoda seek zmienia pooenie wskanika. in. zaczynajc od pocztku acucha.seek((n .seek((n . Metoda writeFixedString zapisuje okrelon liczb kodów. Wskanik pliku opisuje pozycj nastpnego bajta. jak i DataOutput.dat". Zaómy na przykad. e chcemy ustawi wskanik pliku na trzecim rekordzie. uywamy tych samych metod. . aby przywróci wskanik pliku na pocztek tego rekordu: in. "rw"). W przypadku acuchów znaków sytuacja jest nieco trudniejsza. Cakowit liczb rekordów w pliku ustalamy. RandomAccesFile inOut = new RandomAccesFile("employee. Plik o swobodnym dostpie moemy otworzy w trybie tylko do odczytu albo zarówno do odczytu. e. RandomAccesFile in = new RandomAccesFile("employee. (Jeli jest ich za mao. Przeledzimy teraz dziaanie programu.1) * RECORD_SIZE). Otwarcie istniejcego pliku przy uyciu RandomAccessFile nie powoduje jego skasowania. Liczby cakowite i zmiennoprzecinkowe posiadaj reprezentacj binarn o staej liczbie bajtów. jak i do zapisu.Rozdzia 1. Okrelamy to. Kady z rekordów bdzie mie ten sam rozmiar.

MONTH) + 1). calendar. Dla lepszej efektywnoci metoda uywa klasy StringBuilder do wczytania acucha. } } Metoda readFixedString wczytuje size kodów znaków ze strumienia wejciowego lub do momentu napotkania wartoci zerowej. Techniki zaawansowane public static void writeFixedString(String s. public static String readFixedString(int size. salary = in.writeInt(calendar.readDouble().get(Calendar. out). boolean more = true.append(ch). public void readData(DataInput in) throws IOException { name = DataIO.readChar(). int size.YEAR)). out. Wszystkie pozostae wartoci zerowe zostaj pominite. i++) { char ch = 0. zapisujemy po prostu wszystkie jego pola w formacie binarnym.DAY_OF_MONTH)). int y = in. public void writeData(DataOutput out) throws IOException { DataIO.writeInt(calendar. out.writeInt(calendar. } in. Aby zapisa rekord o staym rozmiarze. } Metody writeFixedString i readFixedString umiecilimy w klasie pomocniczej DataIO.get(Calendar.get(Calendar.skipBytes(2 * (size . while (more && i < size) { char ch = in.writeDouble(salary). if (i < s.setTime(hireDay). int i = 0. else b. in). NAME_SIZE. return b. int m = in.i)).writeFixedString(name.readInt(). i++.readFixedString(NAME_SIZE. out.charAt(i).readInt(). } Odczyt rekordu jest równie prosty.44 Java.length()) ch = s. i < size. out. DataOutput out) throws IOException { for (int i = 0. if (ch == 0) more = false. . GregorianCalendar calendar = new GregorianCalendar(). out.writeChar(ch). DataInput in) throws IOException { StringBuilder b = new StringBuilder(size).toString().

d).1. Q Strumienie i pliki 45 int d = in. } Wyznaczmy jeszcze rozmiar kadego rekordu. GregorianCalendar calendar = new GregorianCalendar(y. m . hireDay = calendar. .Rozdzia 1.readInt().getTime().

RECORD_SIZE). W rezultacie kady rekord bdzie zajmowa 100 bajtów: Q 40 znaków = 80 bajtów dla pola name Q 1 double = 8 bajtów dla pola salary Q 3 int = 12 bajtów dla pola date Program przedstawiony na listingu 1.*. poniewa najpierw zostanie wczytany ostatni rekord.dat")). out. a nastpnie wczytuje je w odwrotnej kolejnoci. in.dat". i >= 0. 1989.acuchy znakowe przechowujce nazwiska bd miay 40 znaków dugoci. 3.11 2004-05-11 * @author Cay Horstmann */ public class RandomFileTest { public static void main(String[] args) { Employee[] staff = new Employee[3].1. // wczytuje wszystkie rekordy do nowej tablicy RandomAccessFile in = new RandomAccessFile("employee.writeData(out). staff[0] = new Employee("Carl Cracker". 40000. /** * @version 1. // oblicza rozmiar tablicy int n = (int)(in.length() / Employee.seek(i * Employee. 12. try { // zapisuje rekordy wszystkich pracowników w pliku employee.*.2. import java.util.RECORD_SIZE). 10. RandomFileTest. staff[1] = new Employee("Harry Hacker".java import java. 1). 75000. Employee[] newStaff = new Employee[n]. "r"). Listing 1. // wczytuje rekordy pracowników w odwrotnej kolejnoci for (int i = n . .close(). 50000.io.dat DataOutputStream out = new DataOutputStream(new ´FileOutputStream("employee. for (Employee e : staff) e. staff[2] = new Employee("Tony Tester". i--) { newStaff[i] = new Employee(). 1987.2 zapisuje trzy rekordy w pliku danych. Efektywne dziaanie programu wymaga pliku o swobodnym dostpie. 15). 1990. 15).

salary = s. } public double getSalary() { return salary. double s. } public String getName() { return name. int day) { name = n. } /** Podnosi wynagrodzenie pracownika. } in. month . } public Date getHireDay() { return hireDay. } public String toString() { return getClass(). int month.salary=" + salary .println(e). hireDay = calendar.readData(in).close().getTime().46 Java. Techniki zaawansowane newStaff[i]. day). salary += raise. int year.printStackTrace(). @byPercent podwyka procentowo */ public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100. } catch (IOException e) { e. } } } class Employee { public Employee() {} public Employee(String n. // wywietla wczytane rekordy for (Employee e : newStaff) System.1. GregorianCalendar calendar = new GregorianCalendar(year.getName() + "[name=" + name + ".out.

private Date hireDay.readChar(). out.get(Calendar. GregorianCalendar calendar = new GregorianCalendar(y.readInt(). NAME_SIZE.get(Calendar. } /** Zapisuje dane pracownika @param out obiekt klasy DataOutput */ public void writeData(DataOutput out) throws IOException { DataIO. } /** Wczytuje dane pracownika @param in obiekt klasy DataOutput */ public void readData(DataInput in) throws IOException { name = DataIO.writeInt(calendar. out.writeFixedString(name.YEAR)). in).append(ch).setTime(hireDay). i++. private double salary.MONTH) + 1). int i = 0.readInt(). int d = in.readInt(). } class DataIO { public static String readFixedString(int size. GregorianCalendar calendar = new GregorianCalendar(). out. 47 .writeDouble(salary).Rozdzia 1. out). salary = in. while (more && i < size) { char ch = in.hireDay=" + hireDay + "]". int m = in. else b.readDouble().get(Calendar. int y = in. boolean more = true. hireDay = calendar.DAY_OF_MONTH)). if (ch == 0) more = false. } public static final int NAME_SIZE = 40. m . private String name. public static final int RECORD_SIZE = 2 * NAME_SIZE + 8 + 4 + 4 + 4. Q Strumienie i pliki + ".readFixedString(NAME_SIZE. calendar.writeInt(calendar. d).getTime(). DataInput in) throws IOException { StringBuilder b = new StringBuilder(size). out.writeInt(calendar.1.

skipBytes(2 * (size .RandomAccessFile 1. Techniki zaawansowane } in. int size. Kady plik ZIP posiada nagówek zawierajcy informacje. DataOutput out) throws IOException { for (int i = 0. i < size. } public static void writeFixedString(String s. long getFilePointer() zwraca aktualne pooenie wskanika pliku. Q long length() zwraca dugo pliku w bajtach. w których mona przechowywa jeden lub wicej plików w postaci (zazwyczaj) skompresowanej. if (i < s.io.48 Java. String mode) Q RandomAccessFile(File file. W jzyku Java. Odczyt dotyczy okrelonej pozycji w archiwum.toString(). Strumienie plików ZIP Pliki ZIP to archiwa. takie jak nazwa pliku i uyta metoda kompresji.0 Q RandomAccessFile(String file. "rws" dla odczytu i zapisu danych wraz z synchronicznym zapisem danych i metadanych dla kadej aktualizacji. "rwd" dla odczytu i zapisu danych wraz z synchronicznym zapisem tylko samych danych.i)). "r" dla samego odczytu. aby czyta z pliku ZIP. } } } java. out. korzystamy z klasy ZipInputStream. Metoda read klasy Zip . który ma zosta otwarty. Q void seek(long pos) zmienia pooenie wskanika pliku.writeChar(ch).length()) ch = s. Metoda getNext ´Entry zwraca obiekt typu ZipEntry opisujcy pozycj archiwum. przesuwajc go o pos bajtów od pocztku pliku.charAt(i). String mode) Parametry: file tryb Q plik. i++) { char ch = 0. "rw" dla odczytu i zapisu. return b.

Dla przykadu. aby wydoby z archiwum ZIP plik tekstowy. ksiki Java 2. Pliki JAR (omówione w rozdziale 10. Po zakoczeniu zapisu pliku wywoujemy metod closeEntry. Zazwyczaj dzieje si tak. while (in.nextLine(). moemy zmieni ich wartoci. Dla kadej pozycji. manifest. Nazw pliku przekazujemy konstruktorowi ZipEntry. wywoujemy metod putNextEntry klasy ZipOutputStream. ródo .getNextEntry()) != null) { analizuj entry. Odczytujc dane przechowywane w skompresowanej postaci. zout. Aby rozpocz zapis nowego pliku w archiwum. Wczytujc zawarto pozycji pliku ZIP. Strumie wejcia ZIP wyrzuca wyjtek ZipException.closeEntry(). Jeli chcemy. ZipOutputStream zout = new ZipOutputStream(fout). Oto typowy kod wczytujcy zawarto pliku ZIP: ZipInputStream zin = ZipInputStream (new FileInputStream(zipname)). tzw. zin.zip"). musimy wtedy wywoa metod close ´Entry. wczytaj zawarto zin. takie jak data pliku i metoda dekompresji. które chcemy skompresowa w archiwum. wylij dane do zout. któr chcemy umieci w archiwum ZIP. zout. Nastpnie wysyamy dane do strumienia ZIP. Oto schemat kodu: FileOutputStream fout = new FileOutputStream("test.Rozdzia 1. tworzymy obiekt ZipEntry.closeEntry(). Aby zapisa dane do pliku ZIP. Strumienie ZIP s dobrym przykadem potgi abstrakcji strumieni. gdy napotka koniec pozycji archiwum. jeeli w czasie czytania pliku ZIP nastpi bd. Aby odczyta kolejn pozycj archiwum. konstruktor sam okrela inne parametry. zwykle zamiast z podstawowej metody read lepiej bdzie skorzysta z jakiego bardziej kompetentnego filtru strumienia. a nie koniec caego pliku ZIP.hasNextLine()) operacje na in. dla wszystkich plików { ZipEntry ze = new ZipEntry(nazwapliku). nie musimy zajmowa si ich dekompresj.close(). moemy skorzysta z poniszej ptli: Scanner in = new Scanner(zin). Q Strumienie i pliki 49 ´InputStream zwraca warto –1.close(). } zin. while ((entry = zin. gdy archiwum zostao uszkodzone. Podstawy s po prostu plikami ZIP. uywamy strumie ZipOutputStream. } zout. Wymienione operacje powtarzamy dla wszystkich plików.putNextEntry(kze). Do wczytania i zapisania manifestu uywamy klas JarInputStream i JarOutputStream. zawierajcymi specjalny rodzaj pliku. ZipEntry entry.

setSize(DEFAULT_WIDTH.*. java. * list pozwalajc na wybór plików w archiwum * oraz menu pozwalajce wczyta nowe archiwum. /** * @version 1.32 2007-06-22 * @author Cay Horstmann */ public class ZipTest { public static void main(String[] args) { EventQueue. frame.*. ZipTest.*.setVisible(true).util. gdy mechanizm adowania klas jakiego apletu wczytuje plik JAR.util. Na przykad za kadym razem.util.*.invokeLater(new Runnable() { public void run() { ZipTestFrame frame = new ZipTestFrame().setDefaultCloseOperation(JFrame.awt.awt.50 Java. DEFAULT_HEIGHT). Techniki zaawansowane bajtów formatu ZIP nie musi by plikiem — dane ZIP mog by cigane przez poczenie sieciowe.*.3. Listing 1. tak naprawd wczytuje i dekompresuje dane pochodzce z sieci. Artyku dostpny pod adresem http://www.java import import import import import import import java.EXIT_ON_CLOSE). // dodaje menu i opcje Open oraz Exit . } }).List.5. java. jego zawarto zostanie wywietlona w obszarze tekstowym.swing. */ class ZipTestFrame extends JFrame { public ZipTestFrame() { setTitle("ZipTest").*.3 pozwala uytkownikowi otworzy archiwum ZIP. w dolnej czci okna. javax. java.event.javaworld. Program przedstawiony na listingu 1. } } /** * Ramka zawierajca obszar tekstowy wywietlajcy zawarto pliku. java.zip. tak jak jest to pokazane na rysunku 1. Jeeli uytkownik kliknie dwukrotnie który z plików.html przedstawia sposób modyfikacji archiwum ZIP.com/javaworld/jw-10-2000/ ´jw-1027-toolbox. java.io. frame. Nastpnie wywietla pliki przechowywane w tym archiwum w postaci listy.

JMenuItem exitItem = new JMenuItem("Exit"). } } }).addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { JFileChooser chooser = new JFileChooser(). setJMenuBar(menuBar). fileCombo = new JComboBox(). int r = chooser.getPath().add(menu). scanZipFile(). menuBar.Rozdzia 1.5. menu. openItem. fileCombo.this).")).addActionListener(new ActionListener() Strumienie i pliki 51 .removeAllItems(). // dodaje obszar tekstowy i list fileText = new JTextArea(). fileCombo. if (r == JFileChooser.setCurrentDirectory(new File(". chooser. Program ZipTest w dziaaniu JMenuBar menuBar = new JMenuBar(). menu.add(exitItem). JMenu menu = new JMenu("File").getSelectedFile().APPROVE_OPTION) { zipname = chooser.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { System. Q Rysunek 1.showOpenDialog(ZipTestFrame. } }). exitItem.exit(0). JMenuItem openItem = new JMenuItem("Open").add(openItem).

SOUTH).execute(). zin. while ((entry = zin.getNextEntry()) != null) { publish(entry.CENTER).closeEntry(). } /** * Skanuje zawarto archiwum ZIP i wypenia list. } protected void process(List<String> names) { for (String name : names) fileCombo. BorderLayout. BorderLayout. } }). String>() { protected Void doInBackground() throws Exception { ZipInputStream zin = new ZipInputStream(new ´FileInputStream(zipname)). add(fileCombo. new SwingWorker<Void.addItem(name).52 Java. add(new JScrollPane(fileText). } /** * aduje zawarto pliku z archiwum ZIP * do obszaru tekstowego * @param name nazwa pliku w archiwum */ public void loadZipFile(final String name) { fileCombo. Void>() { protected Void doInBackground() throws Exception { try { . fileText.setText("").setEnabled(false).getSelectedItem()). ZipEntry entry. } }.close(). return null. */ public void scanZipFile() { new SwingWorker<Void. Techniki zaawansowane { public void actionPerformed(ActionEvent event) { loadZipFile((String) fileCombo. } zin.getName()).

public static final int DEFAULT_HEIGHT = 300.closeEntry().execute(). ZipEntry entry.setEnabled(true). jeeli archiwum nie ma wicej pozycji. } public static final int DEFAULT_WIDTH = 400.close(). 53 .append(in.getName(). } }. private JComboBox fileCombo.getNextEntry()) != null) { if (entry. private String zipname. // znajduje element archiwum o odpowiedniej nazwie while ((entry = zin. } return null. fileText.zip.Rozdzia 1. while (in. } protected void done() { fileCombo.hasNextLine()) { fileText. Q Strumienie i pliki ZipInputStream zin = new ZipInputStream(new ´FileInputStream(zipname)). Q ZipEntry getNextEntry() zwraca obiekt typu ZipEntry opisujcy nastpn pozycj archiwum lub null.util.ZipInputStream 1.append("\n"). } } zin. } zin.nextLine()). } java.equals(name)) { // wczytuje go do obszaru tekstowego Scanner in = new Scanner(zin).1 Q ZipInputStream(InputStream in) tworzy obiekt typu ZipInputStream umoliwiajcy dekompresj danych z podanego strumienia InputStream.printStackTrace(). private JTextArea fileText. } catch (IOException e) { e.

1 Q ZipEntry(String name) Parametry: Q name nazwa elementu. Q boolean isDirectory() zwraca warto logiczn. Q void closeEntry() zamyka aktualnie otwart pozycj archiwum ZIP. jeeli rozmiar nie jest znany.zip.ZipOutputStream 1.1 Q ZipOutputStream(OutputStream out) tworzy obiekt typu ZipOutputStream. jeeli podany stopie jest nieprawidowy.ZipEntry 1. Q void setLevel(int level) okrela domylny stopie kompresji nastpnych pozycji archiwum o trybie DEFLATED. Techniki zaawansowane Q void closeEntry() zamyka aktualnie otwart pozycj archiwum ZIP. dla których metoda kompresji nie zostaa okrelona. Q void setMethod(int method) okrela domyln metod kompresji dla danego ZipOutputStream dla wszystkich pozycji archiwum. java. wywoujc metod getNextEntry(). od 0 (NO_COMPRESSION) do 9 (BEST_COMPRESSION). który umoliwia kompresj i zapis danych w podanym strumieniu OutputStream. Q void putNextEntry(ZipEntry ze) zapisuje informacje podanej pozycji ZipEntry do strumienia i przygotowuje strumie do odbioru danych.54 Java. Dane mog zosta zapisane w strumieniu przy uyciu metody write(). Domyln wartoci jest Deflater. wywoujemy metod putNextEntry.DEFAULT_COMPRESSION. czy dany element archiwum jest katalogiem. Q long getSize() zwraca rozmiar danego elementu po dekompresji lub –1. Aby otworzy nastpn pozycj. Q String getName() zwraca nazw elementu. Dziki temu moemy odczyta nastpn pozycj.util. .zip. Parametry: method metoda kompresji.util. DEFLATED lub STORED. java. Wyrzuca wyjtek IllegalArgumentException. Parametry: level stopie kompresji. long getCrc() zwraca warto sumy kontrolnej CRC32 danego elementu. która okrela.

Strumienie obiektów i serializacja Korzystanie z rekordów o staej dugoci jest dobrym rozwizaniem. Q ZipEntry getEntry(String name) zwraca element archiwum o podanej nazwie lub null. jeeli taki element nie istnieje. DEFLATED lub STORED. Aby obliczy t sum uywamy klasy CRC32. otwarty do odczytu. java. Dla przykadu: moemy uywa tablicy o nazwie staff. na podstawie podanego acucha lub obiektu typu File. pod warunkiem e zapisujemy dane tego samego typu.ZipFile 1. element ZipEntry w pliku ZIP. Q void setCrc(long crc) okrela sum kontroln CRC32 dla danego elementu. Q ZipFile(File file) tworzy obiekt typu ZipFile. na podstawie podanego acucha. np.Rozdzia 1. rzadko nale do tego samego typu. Q Enumeration entries() zwraca obiekt typu Enumeration.util. jeeli metod kompresji jest STORED. Parametry: name nazwa elementu. której nominalnym typem jest Employee. Wymagana. ale która zawiera obiekty bdce instancjami klas pochodnych. klasy Manager. jeeli metod kompresji jest STORED. Q InputStream getInputStream(ZipEntry ze) zwraca obiekt InputStream dla podanego elementu. . void setSize(long rozmiar) okrela rozmiar elementu. które tworzymy w programie zorientowanym obiektowo. Parametry: ze Q String getName() zwraca ciek dostpu do pliku ZIP. Jednak obiekty. wyliczajcy obiekty ZipEntry opisujce elementy archiwum ZipFile. otwarty do odczytu. Q Strumienie i pliki 55 void setMethod(int method) Parametry: Q Q method metoda kompresji danego elementu.1 Q ZipFile(String name) ten konstruktor tworzy obiekt typu ZipFile. Wymagana. Parametry: rozmiar rozmiar nieskompresowanego elementu. Parametry: crc suma kontrolna elementu.

1). który omówilimy w rozdziale 6. Aby móc serializowa . zmodyfikujemy troch klas Manager. wywoujemy metod writeObject klasy ObjectOutputStream: Employee harry = new Employee("Harry Hacker". skd wzi si termin „serializacja”). . Pozwala on na wysanie do strumienia dowolnego obiektu i umoliwia jego póniejsze wczytanie (w dalszej czci tego rozdziau wyjanimy. Techniki zaawansowane Z pewnoci mona zaprojektowa format danych. który pozwoli przechowywa takie polimorficzne kolekcje. Jednake musimy rozway jeszcze jedn sytuacj.readObject(). uywamy strumienia ObjectInputStream: ObjectInputStream in = new ObjectInputStream(new FIleInputStream("employee. Podstawy. out. Nastpnie pobieramy z niego obiekty w tym samym porzdku. 1989. to konieczne jest wprowadzenie jednej modyfikacji w klasie tych obiektów. korzystajc z metody readObject: Employee p1 = (Employee)in.writeObject(harry). 12. . Co si stanie. w jakim zostay zapisane. musimy najpierw otworzy strumie ObjectOutputStream: ObjectOutputStream out = new ObjectOutputStream(new ´FileOutputStream("employee. Manager boss = new Manager("Carl Cracker". out.dat")). 15). Employee p2 = (Employee)in.dat")). Aby jednak móc klonowa obiekty. Klasa ta musi implementowa interfejs Serializable: class Employee implements Serializable { . } Kady obiekt typu Manager przechowuje teraz referencj do obiektu klasy Employee opisujcego asystenta. Jeli chcemy zapisywa i odtwarza obiekty za pomoc strumieni obiektów. jeeli dany obiekt jest wspódzielony przez kilka innych obiektów jako element ich stanu? Aby zilustrowa ten problem. Teraz. Zaómy. aby zapisa obiekt. Jzyk Java obsuguje bowiem bardzo ogólny mechanizm zwany serializacj obiektów. nie musimy zatem wprowadza adnych innych modyfikacji naszych klas. . Aby z powrotem zaadowa obiekty. 10. Aby zachowa dane obiektu. a nie osobn kopi tego obiektu. } Interfejs Serializable nie posiada metod. private Employee secretary.readObject(). nie naley robi nic poza dopisaniem powyszych sów. ksiki Java 2. Pod tym wzgldem Serializable jest podobny do interfejsu Cloneable. musimy przesoni metod clone klasy Object. . e kady meneder ma asystenta: class Manager extends Employee { . 1987. . 50000. ale na szczcie ten dodatkowy wysiek nie jest konieczny.56 Java. 80000.writeObject(boss).

Dwóch menederów moe mie wspólnego asystenta Teraz zaómy. Q Jeeli obiekt zosta ju zapisany. carl. . Q Jeli referencja do obiektu zostaa napotkana po raz pierwszy. tak jak zostao to przedstawione na rysunku 1.). e w danym miejscu znajduje si „ten sam obiekt. . Java odwraca ca procedur. inicjuje danymi ze strumienia i zapamituje zwizek pomidzy numerem i referencj do obiektu. Oczywicie nie moemy zapisa i przywróci adresów obiektów asystentów.Rozdzia 1.6. . . . Wczytujc obiekty z powrotem. Q Strumienie i pliki 57 Oznacza to. tony. .setSecretary(harry). . e dwóch menederów moe mie tego samego asystenta. Java zapisuje. .setSecretary(harry). Java tworzy go. Zamiast tego kady obiekt zostaje zapisany z numerem seryjnym i std wanie pochodzi okrelenie serializacja. . Q Gdy obiekt pojawia si w strumieniu po raz pierwszy. obiekt zostaje zapisany w strumieniu. e zapisujemy dane pracowników na dysk. poniewa po ponownym zaadowaniu obiekt asystenta najprawdopodobniej znajdzie si w zupenie innym miejscu pamici. Oto jej algorytm: Q Wszystkim napotkanym referencjom do obiektów nadawane s numery seryjne (patrz rysunek 1.6 i w poniszym kodzie: harry = new Employee("Harry Hacker". .).).7). Manager carl = new Manager("Carl Cracker". Manager tony = new Manager("Tony Tester". co pod numerem seryjnym x”. Rysunek 1.

co pod numerem seryjnym x”.7.util. Podobnie jak adresy pamici s bezuyteczne dla pliku. import java. moemy transportowa zbiory danych z jednej maszyny na drug. znajduje to odzwierciedlenie za pomoc pól secretary obiektów klasy Manager. gdzie znajduje si obiekt o danym numerze. i nadaje referencji do obiektu adres tego miejsca. Zwró uwag. sprawdza. Listing 1. ObjectStreamTest. a pó niej z powrotem je wczyta . Przykad serializacji obiektów Q Gdy natrafi na znacznik „ten sam obiekt.58 Java. Poniewa serializacja zastpuje adresy pamici numerami seryjnymi. Innym bardzo wanym zastosowaniem serializacji jest przesyanie obiektów przez sie na inny komputer.10 17 Aug 1998 * @author Cay Horstmann */ class ObjectStreamTest { public static void main(String[] args) . /** * @version 1.*. W tym rozdziale korzystamy z serializacji.java import java.io. Omówimy to zastosowanie przy okazji wywoywania zdalnych metod w rozdziale 5. tak samo s bezuyteczne dla innego rodzaju procesora. e po wczytaniu istnieje tylko jeden obiekt kadego asystenta — gdy pracownik newStaff[1] dostaje podwyk.4.4 zawiera program zapisujcy i wczytujcy sie powizanych obiektów klas Employee i Manager (niektóre z nich maj referencj do tego samego asystenta).*. Listing 1. Techniki zaawansowane Rysunek 1. aby zapisa zbiór obiektów na dysk.

setSecretary(harry). 1990. try { // zapisuje rekordy wszystkich pracowników w pliku employee.setSecretary(harry).printStackTrace().dat")). } } } class Employee implements Serializable { public Employee() { } public Employee(String n. carl. salary = s. Manager tony = new Manager("Tony Tester". Employee[] newStaff = (Employee[]) in. month .out. hireDay = calendar.dat ObjectOutputStream out = new ObjectOutputStream(new ´FileOutputStream("employee. 15). out.1. 50000. 1).Rozdzia 1. tony. 3.close().println(e). Q Strumienie i pliki { Employee harry = new Employee("Harry Hacker".dat")). int day) { name = n.raiseSalary(10). int month.getTime(). Employee[] staff = new Employee[3]. 40000. 1987. day). } catch (Exception e) { e. in. staff[1] = harry. out. Manager carl = new Manager("Carl Cracker". } public String getName() { 59 . 80000.close().readObject(). 1989. staff[2] = tony. 15). // wczytuje wszystkie rekordy do nowej tablicy ObjectInputStream in = new ObjectInputStream(new ´FileInputStream("employee. // wywietla wszystkie rekordy for (Employee e : newStaff) System. GregorianCalendar calendar = new GregorianCalendar(year. double s. 12.writeObject(staff). 10. staff[0] = carl. // podnosi wynagrodzenie asystenta newStaff[1]. int year.

private Date hireDay. int month. } private String name. double s. } public double getSalary() { return salary. * @param s asystent */ public void setSecretary(Employee s) { secretary = s. secretary = null. year. } public String toString() { return getClass(). salary += raise. } class Manager extends Employee { /** * Tworzy obiekt klasy Manager nie inicjujc pola secretary * @param n nazwisko pracownika * @param s wynagrodzenie * @param year rok zatrudnienia * @param month miesic zatrudnienia * @param day dzie zatrudnienia */ public Manager(String n. } . } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100. month. int year. private double salary.getName() + "[name=" + name + ".hireDay=" + hireDay + "]".salary=" + salary + ´". Techniki zaawansowane return name. } public Date getHireDay() { return hireDay. day). } /** * Przypisuje asystenta menederowi.60 Java. s. int day) { super(n.

którym aktualnie jest 00 05 (w tym podrozdziale do opisywania bajtów bdziemy uywa notacji szesnastkowej). java. w takiej kolejnoci. sygnatur klasy oraz wartoci wszystkich niestatycznych. } private Employee secretary. dziki któremu moesz zapisywa obiekty do podanego strumienia wyjcia. która sekwencja bajtów reprezentuje dany obiekt w pliku. nie wiedzc nawet. Q Object readObject() wczytuje obiekt z ObjectInputStream. Metoda ta zachowuje klas obiektu.io. moesz pomin lektur tego podrozdziau.ObjectInputStream 1.1 Q ObjectInputStream(InputStream we) tworzy obiekt ObjectInputStream. Kady plik zaczyna si dwubajtow „magiczn liczb”: AC ED po której nastpuje numer wersji formatu serializacji obiektów. sygnatur klasy oraz wartoci wszystkich niestatycznych. to jeli nie jeste zainteresowany implementacj serializacji. } java. Format pliku serializacji obiektów Serializacja obiektów powoduje zapisanie danych obiektu w okrelonym formacie. Q Strumienie i pliki 61 public String toString() { return super.io. pozwalajc na przyporzdkowanie obiektów referencjom. . Przeprowadza deserializacj. a take jej nadklas. moemy uywa metod writeObject/readObject. dziki któremu moesz odczytywa informacje z podanego strumienia wejcia.ObjectOutputStream 1. nieprzechodnich pól skadowych tej klasy.toString() + "[secretary=" + secretary + "]". Q void writeObject(Object ob) zapisuje podany obiekt do ObjectOutputStream. a take jej nadklas. w jakiej zostay one zapisane. Poniewa poniszy tekst jest peen technicznych detali.Rozdzia 1. Oczywicie.1 Q ObjectOutputStream(OutputStream wy) tworzy obiekt ObjectOutputStream. Póniej nastpuje sekwencja obiektów. e poznanie formatu danych bdzie bardzo pomocne. nieprzechodnich pól skadowych tej klasy. Pobiera klas obiektu. Niemniej jednak doszlimy do wniosku. poniewa daje wgld w proces obsugi obiektów przez strumienie.

62 Java. Techniki zaawansowane .

autorstwa Williama Stallingsa. interfejsów. Niezalenie od rozmiaru oryginalnych danych. W chwili odczytu danych Java sprawdza. pobierajc opisy klasy. w jaki sposób przechowywany jest identyfikator klasy: 72 dugo nazwy klasy (2 bajty) nazwa klasy „odcisk” klasy (8 bajtów) zbiór flag (1 bajt) liczba deskryptorów pól skadowych (2 bajty) deskryptory pól skadowych . uywajc „odcisku” klasy. Mimo to nadal jest bardzo prawdopodobne. a nastpnie stosuje do nich algorytm SHA (Secure Hash Algorithm). zajrzyj np. acuch "Harry" bdzie wyglda tak: 74 00 05 Harry Znaki Unicode zapisywane s w zmodyfikowanym formacie UTF-8. czy definicja klasy nie ulega zmianie. Q opis pól skadowych. aby dowiedzie si wicej o SHA. jeeli ulegn zmianie pola skadowe lub metody. Oto. do Cryptography and Network Security: Principle and Practice. Oczywicie. e jeeli zachowana informacja zmieni si. SHA jest amerykaskim standardem. „odciskiem” jest zawsze pakiet 20 bajtów. Q zbiór flag opisujcy metod serializacji. rekomendowanym przez Narodowy Instytut Nauki i Technologii (National Institute of Science and Technology — NIST. e program bdzie musia wczyta starsze wersje obiektów. wydanej przez Prentice Hall). typów pól danych oraz sygnatury metod w postaci kanonicznej. klasy bazowej. Q unikalny numer ID stanowicy „odcisk” wszystkich danych skadowych i sygnatur metod. SHA to szybki algorytm. Jednake Java korzysta jedynie z pierwszych omiu bajtów kodu SHA. dziki którym moemy mie stuprocentow pewno . Java tworzy wspomniany „odcisk” klasy. e „odcisk” zmieni si. Wraz z obiektem musi zosta zapisana jego klasa. Opis klasy zawiera: Q nazw klasy.acuchy zapisywane s jako 74 dugo (2 bajty) znaki Dla przykadu. tworzcy „odciski palców” dla duych bloków danych. w praktyce klasy ulegaj zmianie i moe si okaza . zmianie ulegnie równie jej „odcisk palca”. Zagadnienie to omówimy w punkcie „Wersje” na stronie 71. Jest on tworzony za pomoc sekwencji operacji binarnych.

util. Kady deskryptor pola skadowego skada si z nastpujcych elementów: Q kod typu (1 bajt). // klasa implementuje interfejs Serializable static final byte SC_EXTERNALIZABLE = 4. Jednak np. . jeli nie istnieje) Bajt flag skada si z trzybitowych masek. Q nazwa pola. Q Strumienie i pliki 63 78 (znacznik koca) typ klasy bazowej (70. Klasy implementujce Exter ´nalizable udostpniaj wasne metody wczytujce i zapisujce. Klasy. zaraz za nazw pola skadowego znajdzie si nazwa jego typu. zdefiniowanych w java. // klasa posiada metod writeObject zapisujc dodatkowe dane static final byte SC_SERIALIZABLE = 2.ObjectStreamCon ´stants: java.io. Q nazwa klasy (jeeli pole skadowe jest obiektem).ObjectStreamConstants: static final byte SC_WRITE_METHOD = 1.Date implementuje Externa ´lizable i jej bajt flag ma warto 03. Q dugo nazwy pola (2 bajty). Kod typu moe mie jedn z nastpujcych wartoci: B byte C char D double F float I int J long L obiekt S short Z boolean [ tablica Jeeli kodem typu jest L. // klasa implementuje interfejs Externalizable Interfejs Externalizable omówimy w dalszej czci rozdziau. które budujemy. implementuj interfejs Serializable i bd mie bajt flag o wartoci 02. klasa java.io.Rozdzia 1. które przejmuj obsug nad swoimi polami skadowymi.

Dla przykadu. pole pensji klasy Employee zostanie zapisane jako: D 00 06 salary .acuchy nazw klas i pól skadowych nie zaczynaj si od 74. w przeciwiestwie do typów pól skadowych. Typy pól skadowych uywaj troch innego sposobu kodowania nazw. a dokadniej — formatu uywanego przez metody macierzyste.

78 70 „Odcisk” oraz flagi Liczba pól skadowych Typ i nazwa pola skadowego Typ i nazwa pola skadowego Nazwa klasy pola skadowego — String Typ i nazwa pola skadowego Nazwa klasy pola skadowego — String Znacznik koca Brak nadklasy Opisy te s do dugie. W tym formacie nazwy klas zaczynaj si od L. L 00 04 name 74 00 12 Ljava/lang/String. plik danych zawiera informacje wystarczajce do odtworzenia obiektu klasy Employee. tablica trzech obiektów typu Employee zaczyna si tak: . Dla przykadu. zostanie uyta forma skrócona: 71 numer seryjny (4 bajty) Numer seryjny wskazuje na poprzedni opis danej klasy.64 Java.Date 77 08 00 00 00 91 1B 4E B1 80 78 Zawarto zewntrzna — szczegóy poniej 74 00 0C Harry Hacker Warto pola name — String 40 E8 6A 00 00 00 00 73 Jak widzimy.util. oto zapis obiektu klasy Employee: Warto pola salary — double Warto pola hireDay — nowy obiekt 71 00 7E 00 08 Istniejca klasa java. Obiekt jest przechowywany w nastpujcej postaci: 73 opis klasy dane obiektu Dla przykadu. Techniki zaawansowane A oto kompletny opis klasy Employee: 72 00 08 Employee E6 D2 86 7D AE AC 18 1B 02 00 03 D 00 06 salary L 00 07 hireDay 74 00 10 Ljava/util/Date. Jeeli w pliku jeszcze raz musi si znale opis tej samej klasy. Tablice s zapisywane w nastpujcy sposób: 75 opis klasy liczba elementów (4 bajty) elementy Nazwa klasy tablicy jest zachowywana w formacie uywanym przez metody macierzyste (róni si on troch od formatu nazw innych klas). a kocz rednikiem. Schemat numerowania omówimy póniej.

nazwa klasy Employee[] (nr #0) „Odcisk” oraz flagi Liczba pól skadowych Znacznik koca Brak klasy bazowej Liczba elementów tablicy staff[0] — nowy obiekt (nr #7) .dat w notacji szesnastkowej i porównaj z poniszymi komentarzami. spójrz na zapis pliku employee. FC BF 36 11 C5 91 11 C7 02 00 00 78 70 00 00 00 03 73 Nagówek pliku Tablica staff (nr #1) Nowa klasa. jako 71 plus odpowiedni numer seryjny. Wszystkie obiekty (cznie z tablicami i acuchami) oraz wszystkie opisy klas w chwili zapisywania do pliku otrzymuj numery seryjne. dugo acucha. dugo acucha. czy dany numer seryjny dotyczy opisu klasy. Przekonalimy si ju. który zosta ju wczeniej zapisany. W poprzednim przykadzie kolejna referencja klasy Date zostaa zakodowana w nastpujcy sposób: 71 00 7E 00 08 Ten sam mechanizm jest stosowany dla obiektów. AC ED 00 05 75 72 00 0C [LEmployee. Jeeli zapisywana jest referencja obiektu. czy obiektu. Zwró uwag na wiersze zamieszczone pod koniec pliku. Nastpne opisy po prostu wskazuj na pierwszy. e peny opis jest wykonywany tylko raz dla kadej klasy. 75 72 00 0C [LEmployee.Rozdzia 1. uruchom program. zawierajce referencje zapisanego wczeniej obiektu. nowa referencja zostanie zachowana w dokadnie ten sam sposób. Jeli chcesz. e „odcisk” tablicy obiektów Employee róni si od „odcisku” samej klasy Employee. nazwa klasy Employee[] „Odcisk” oraz flagi Liczba pól skadowych Znacznik koca Brak nadklasy Liczba komórek tablicy Zauwamy. FC BF 36 11 C5 91 11 C7 02 00 00 78 70 00 00 00 03 Q Strumienie i pliki 65 Tablica Nowa klasa. Z kontekstu zawsze jasno wynika. wraz z komentarzami. Numery seryjne zaczynaj si od wartoci 00 7E 00 00. Referencja null jest zapisywana jako 70 Oto plik zapisany przez program ObjectRefTest z poprzedniego podrozdziau.

nazwa klasy (nr #2) 36 06 AE 13 63 8F 59 B7 02 „Odcisk” oraz flagi 00 01 Liczba pól skadowych L 00 08 secretary Typ i nazwa pola skadowego 74 00 0B LEmployee. dugo acucha. dugo acucha. Nazwa klasy pola skadowego — String (nr #3) 78 Znacznik koca 72 00 09 Employee Nadklasa — nowa klasa. dugo acucha. Techniki zaawansowane Nowa klasa. Nazwa klasy pola skadowego — String (nr #5) L 00 08 name Typ i nazwa pola skadowego 74 00 12 Ljava/lang/String. Nazwa klasy pola skadowego — String (nr #6) 78 Znacznik koca 70 Brak klasy bazowej F3 88 00 00 00 00 00 Warto pola salary — double Warto pola hireDay — nowy obiekt (nr #9) 72 00 0E java. nazwa klasy (nr #4) E6 D2 86 7D AE AC 18 1B 02 „Odcisk” oraz flagi 00 03 Liczba pól skadowych D 00 06 salary Typ i nazwa pola skadowego L 00 11 hireDay Typ i nazwa pola skadowego 74 00 10 Ljava/util/Date.util.Date Nowa klasa. nazwa klasy (nr #8) 68 6A 81 01 4B 59 74 19 03 „Odcisk” oraz flagi 00 00 Brak zmiennych skadowych 78 Znacznik koca 70 Brak klasy bazowej 77 08 Zawarto zewntrzna.66 Java. liczba bajtów 00 00 00 83 E9 39 E0 00 Data 78 Znacznik koca 00 0C Carl Cracker Warto pola name — String (nr #10) Warto pola secretary — nowy obiekt (nr #11) 71 00 7E 00 04 Istniejca klasa (uyj nr #4) 40 E8 6A 00 00 00 00 00 Warto pola pensja — double 72 00 08 Manager 40 73 74 73 .

Rozdzia 1.
73
71 00 7E 00 08
77 08
00 00 00 91 1B 4E B1 80
78
74 00 0C Harry Hacker
71 00 7E 00 0B
73
71 00 7E 00 08
40 E3 88 00 00 00 00 00
73
71 00 7E 00 08
77 08
00 00 00 94 6D 3E EC 00 00
78
74 00 0D Tony Tester
71 00 7E 00 0B

Q

Strumienie i pliki

67

Warto pola dzienZatrudnienia
— nowy obiekt (nr #12)
Istniejca klasa (uyj nr #8)
Zawarto zewntrzna, liczba bajtów
Data
Znacznik koca
Warto pola name — String (nr #13)
staff[1] — istniejcy obiekt
(uyj nr #11)
obsluga[2] — nowy obiekt (nr #14)
Istniejca klasa (uyj nr #4)
Warto pola salary — double
Warto pola hireDay
— nowy obiekt (nr #15)
Istniejca klasa (uyj nr #8)
Zawarto zewntrzna, liczba bajtów
Data
Znacznik koca
Warto pola name — String (nr #16)
Warto pola secretary — istniejcy
obiekt (uyj nr #11)

Zazwyczaj znajomo dokadnego format pliku nie jest wana (o ile nie próbujesz dokona
zmian w samym pliku).
Powinnimy jednak pamita , e:
Q

strumie obiektów zapisuje typy i pola skadowe wszystkich obiektów,

Q

kademu obiektowi zostaje przypisany numer seryjny,

Q

powtarzajce si odwoania do tego samego obiektu s przechowywane jako
referencje jego numeru seryjnego.

Modyfikowanie domylnego mechanizmu serializacji
Niektóre dane nie powinny by serializowane — np. wartoci typu integer reprezentujce
uchwyty plików lub okien, czytelne wycznie dla metod rodzimych. Gdy wczytamy takie dane
ponownie lub przeniesiemy je na inn maszyn, najczciej oka si bezuyteczne. Co gorsza,
nieprawidowe wartoci tych zmiennych mog spowodowa bdy w dziaaniu metod rodzimych. Dlatego Java obsuguje prosty mechanizm zapobiegajcy serializacji takich danych.
Wystarczy oznaczy je sowem kluczowym transient. Sowem tym naley równie oznaczy
pola, których klasy nie s serializowalne. Pola oznaczone jako transient s zawsze pomijane w procesie serializacji.

68

Java. Techniki zaawansowane
Mechanizm serializacji na platformie Java udostpnia sposób, dziki któremu indywidualne
klasy mog sprawdza prawidowo danych lub w jakikolwiek inny sposób wpywa na
zachowanie strumienia podczas domylnych operacji odczytu i zapisu. Klasa implementujca
interfejs Serializable moe zdefiniowa metody o sygnaturach
private
throws
private
throws

void readObject(ObjectInputStream in)
IOException, ClassNotFoundException;
void writeObject(ObjectOutputStream out)
IOException;

Dziki temu obiekty nie bd automatycznie serializowane — Java wywoa dla nich powysze
metody.
A oto typowy przykad. Wielu klas nalecych do pakietu java.awt.geom, takich jak na przykad
klasa Point2D.Double, nie da si serializowa . Przypu my zatem, e chcemy serializowa klas
LabeledPoint zawierajc pola typu String i Point2D.Double. Najpierw musimy oznaczy pole
Point2D.Double sowem kluczowym transient, aby unikn wyjtku NotSerializableEx
´ception.
public class LabeledPoint implements Serializable
{
. . .
private String label;
private transient Point2D.Double point;
}

W metodzie writeObject najpierw zapiszemy opis obiektu i pole typu String, wywoujc
metod defaultWriteObject. Jest to specjalna metoda klasy ObjectOutputStream, która moe
by wywoywana jedynie przez metod writeObject klasy implementujcej interfejs Seria
´lizable. Nastpnie zapiszemy wspórzdne punktu, uywajc standardowych wywoa klasy
DataOutput.
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
out.writeDouble(point.getX());
out.writeDouble(point.getY());
}

Implementujc metod readObject, odwrócimy cay proces:
private void readObject(ObjectInputStream in)
throws IOException
{
in.defaultReadObject();
double x = in.readDouble();
double y = in.readDouble();
point = new Point2D.Double(x, y);
}

Innym przykadem jest klasa java.util.Date, która dostarcza wasnych metod readObject
i writeObject. Metody te zapisuj dat jako liczb milisekund, które upyny od pónocy 1 stycznia 1970 roku, czasu UTC. Klasa Date stosuje skomplikowan reprezentacj wewntrzn,

Rozdzia 1.

Q

Strumienie i pliki

69

która przechowuje zarówno obiekt klasy Calendar, jak i licznik milisekund, co pozwala
zoptymalizowa operacje wyszukiwania. Stan obiektu klasy Calendar jest wtórny i nie musi
by zapisywany.
Metody readObject i writeObject odczytuj i zapisuj jedynie dane wasnej klasy. Nie zajmuj
si przechowywaniem i odtwarzaniem danych klasy bazowej bd jakichkolwiek innych informacji o klasie.
Klasa moe równie zdefiniowa wasny mechanizm zapisywania danych, nie ogldajc si na
serializacj. Aby tego dokona , klasa musi zaimplementowa interfejs Externalizable. Oznacza
to implementacj dwóch metod:
public void readExternal(ObjectInputSream in)
throws IOException, ClassNotFoundException;
public void writeExternal(ObjectOutputStream out)
throws IOException;

W przeciwiestwie do omówionych wczeniej metod readObject i writeObject, te metody s
cakowicie odpowiedzialne za zapisanie i odczytanie obiektu, cznie z danymi klasy bazowej.
Mechanizm serializacji zapisuje jedynie klas obiektu w strumieniu. Odtwarzajc obiekt implementujcy interfejs Externalizable, strumie obiektów wywouje domylny konstruktor, a nastpnie metod readExternal. Oto jak moemy zaimplementowa te metody w klasie Employee:
public void readExternal(ObjectInput s)
throws IOException
{
name = s.readUTF();
salary = s.readDouble();
hireDay = new Date(s.readLong());
}
public void writeExternal(ObjectOutput s)
throws IOException
{
s.writeUTF(name);
s.writeDouble(salary);
s.writeLong(hireDay.getTime());
}

Serializacja jest do powolnym mechanizmem, poniewa maszyna wirtualna musi
rozpozna struktur kadego obiektu. Jeeli zaley nam na efektywnoci dziaania,
a jednoczenie chcemy wczytywa i zapisywa du liczb obiektów pewnej klasy, powinnimy rozway moliwo zastosowania interfejsu Externalizable. Artyku na stronie
http://java.sun.com/developer/TechTips/2000/tt0425.html stwierdza, e w przypadku
klasy reprezentujcej pracowników skorzystanie z wasnych metod zapisu i odczytu byo
o 35 – 40% szybsze ni domylna serializacja.
W przeciwiestwie do metod writeObject i readObject, które s prywatne i mog
zosta wywoane wycznie przez mechanizm serializacji, metody writeExternal i read
´External s publiczne. W szczególnoci metoda readExternal potencjalnie moe by
wykorzystana do modyfikacji stanu istniejcego obiektu.

Jeli taki typ wyliczeniowy implemenuje interfejs Serializable.write(value)... Okae si. da wynik negatywny. } private int value. . zanim wprowadzono typ wyliczeniowy w jzyku Java. Zaómy jednak. Techniki zaawansowane Serializacja singletonów i wylicze Szczególn uwag naley zwróci na serializacj obiektów. } Powyszy sposób zapisu by powszechnie stosowany. e porównanie if (saved == Orientation. . Zwró my uwag.70 Java. Przypu my.0. public static final Orientation VERTICAL = new Orientation(2). Obiekty tej klasy moemy porównywa za pomoc operatora ==: if (orientation == Orientation. musimy zdefiniowa specjaln metod serializacji o nazwie readResolve.read().VERTICAL. if (value == 2) return Orientation. private Orientation(int v) { value = v. to domylny sposób serializacji okae si w tym przypadku niewaciwy.HORIZONTAL. out. e mamy starszy kod. . .HORIZONTAL) . . . który tworzy typy wyliczeniowe w nastpujcy sposób: public class Orientation { public static final Orientation HORIZONTAL = new Orientation(1). Musi ona zwróci obiekt. out. return null. .HORIZONTAL i Orientation. . który nastpnie zwróci metoda readObject.VERTICAL. Dziki temu powstan jedynie obiekty Orientation. Jeli metoda readResolve jest zdefiniowana. to nie musimy przejmowa si serializacj — wszystko bdzie dziaa poprawnie. Mimo e konstruktor klasy jest prywatny.HORIZONTAL) . które z zaoenia maj by unikalne.close(). W rzeczywistoci bowiem warto saved jest zupenie nowym obiektem typu Orientation i nie jest ona równa adnej ze staych wstpnie zdefiniowanych przez t klas. Jeli uywamy w programach konstrukcji enum wprowadzonej w Java SE 5.HORIZONTAL. // to nie powinno si zdarzy } . Ma to miejsce w przypadku implementacji singletonów i wylicze. mechanizm serializacji moe tworzy zupenie nowe obiekty tej klasy! Aby rozwiza ten problem. Orientation saved = (Orientation) in. ObjectInputStream in = . e zapisalimy warto typu Orientation i wczytujemy j ponownie: Orientation original = Orientation. e konstruktor klasy Orientation jest prywatny. W naszym przykadzie metoda readResolve sprawdzi pole value i zwróci odpowiedni sta: protected Object readResolve() throws ObjectStreamException { if (value == 1) return Orientation. zostaje wywoana po deserializacji obiektu. ObjectOutputStream out = .

stary obiekt moe posiada wicej lub mniej pól skadowych ni aktualny. musimy zastanowi si. gdy powstan nowe wersje programu. co wersja oryginalna. gdy w danej klasie umiecisz powysz sta.8). ale skorzysta z ju istniejcej wartoci. e jest kompatybilna ze swoj wczeniejsz wersj. } Klasa posiadajca statyczne pole skadowe o nazwie serialVersionUID nie obliczy wasnego „odcisku palca”. Na przykad. . . programu bdcego czci JDK. sposób odczytu danych nie ulegnie zmianie. Wraz ze zmian definicji klasy zmienia si kod SHA. Rysunek 1. . albo te typy danych mog si róni . uruchamiajc serialver Employee otrzymujemy: Employee: static final long serialVersionUID = -876875122904779311L Jeeli uruchomimy serialver z opcj -show. Aby tego dokona .1 { .Rozdzia 1. Od momentu. Q Strumienie i pliki 71 Musimy zatem pamita o zdefiniowaniu metody readResolve dla wszystkich wylicze konstruowanych w tradycyjny sposób i wszystkich klas implementujcych wzorzec singletonu. Czy wersja 1. Dla przykadu.1 bdzie potrafia czyta starsze pliki? Czy uytkownicy wersji 1. Do tego celu uyjemy serialver. Jeli zmieni si tylko metody danej klasy.8. Wersje Jeli uywamy serializacji do przechowywania obiektów. class Employee implements Serializable // wersja 1. a strumie obiektów nie odczyta obiektu o innym „odcisku palca”. program wywietli okno dialogowe (rysunek 1. co si z nimi stanie. public static final long serialVersionUID = -1814239825517340645L. moemy mie pewne problemy. system serializacji bdzie móg odczytywa róne wersje obiektów tej samej klasy. Jednake jeeli zmieni si pole skadowe.0 bd mogli wczytywa pliki tworzone przez now wersj? Na pierwszy rzut oka wydaje si to niemoliwe. Wersja graficzna programu serialver Wszystkie póniejsze wersje tej klasy musz definiowa sta serialVersionUID o tym samym „odcisku palca”. musimy pobra „odcisk palca” wczeniejszej wersji tej klasy. W takim wypadku strumie obiektów spróbuje skonwertowa obiekt na aktualn wersj danej klasy. Jednake klasa moe zaznaczy .

Jeeli aktualna wersja posiada pola skadowe nieobecne w zapisanym obiekcie. Jeeli obiekt w strumieniu posiada pola skadowe nieobecne w aktualnej wersji. Opuszczanie pól skadowych wydaje si by bezbolesne — odbiorca wci posiada dane.10. Rysunek 1. dodatkowe zmienne otrzymuj swoje domylne wartoci (null dla obiektów. Oczywicie. Zaómy.9.10 ilustruje odwrotn sytuacj — program korzystajcy z obiektów 1. strumie nawet nie próbuje konwersji — obiekty s niekompatybilne. Dodatkowe pole department jest ignorowane. Wiele klas inicjalizuje wszystkie pola skadowe. Rysunek 1.9 przedstawia. nieulotne pola skadowe. którymi potrafi manipulowa . Pole department otrzymuje warto null. uywajc przy tym oryginalnej (1. strumie bierze pod uwag wycznie niestatyczne. Odczytywanie obiektu o wikszej liczbie pól Czy ten proces jest bezpieczny? To zaley. Nadawanie wartoci null nie jest ju tak bezpieczne. co si dzieje. Jeeli dwa pola maj te same nazwy. Techniki zaawansowane Strumie obiektów porównuje pola skadowe aktualnej wersji klasy z polami skadowymi wersji znajdujcej si w strumieniu. Oto przykad.72 Java.0. strumie ignoruje te dodatkowe dane. lecz róne typy.0 jest wczytywany przez program korzystajcy z obiektów 2. Teraz wprowadzamy now wersj 2. tak wic metody mog by nieprzygotowane do obsu- . 0 dla liczb i false dla wartoci logicznych).0 klasy Employee. e zapisalimy na dysku pewn liczb obiektów klasy Employee.0) wersji klasy. nadajc im w konstruktorach niezerowe wartoci. gdy obiekt wersji 1. Odczytywanie obiektu o mniejszej liczbie pól Rysunek 1. Rysunek 1. dodajc do niej pole skadowe department.0.0 wczytuje obiekt 2.

10. a nastpnie odczytujemy z powrotem. } } /** Klasa. Serializacja w roli klonowania Istnieje jeszcze jedno. czy zaimplementuje w metodzie readObject dodatkowy kod poprawiajcy wyniki wczytywania rónych wersji danych. // modyfikuje obiekt harry harry.20 17 Aug 1998 @author Cay Horstmann */ import java.Rozdzia 1. */ class SerialCloneable implements Cloneable. Kod z listingu 1. ciekawe zastosowanie mechanizmu serializacji — umoliwia on atwe klonowanie obiektów klas implementujcych interfejs Serializable.io. czy te doczy do metod obsug wartoci null. Q Strumienie i pliki 73 giwania wartoci null.out. W efekcie otrzymujemy nowy obiekt.println(harry2). // teraz obiekt harry i jego klon s róne System. 1989. System. // klonuje obiekt harry Employee harry2 = (Employee) harry.raiseSalary(10). bdcy dokadn kopi istniejcego obiektu. Od projektanta klasy zaley. której metoda clone wykorzystuje serializacj. SerialCloneTest.5.5 udowadnia. 35000.java /** @version 1.util. e aby otrzyma metod clone „za darmo”.*. Serializable { public Object clone() { try { // zapisuje obiekt w tablicy bajtów ByteArrayOutputStream bout = new ByteArrayOutputStream(). po prostu zapisujemy go w strumieniu.*. Listing 1.clone(). public class SerialCloneTest { public static void main(String[] args) { Employee harry = new Employee("Harry Hacker". import java. Aby sklonowa obiekt. 1).out. wystarczy rozszerzy klas SerialCloneable.println(harry). . Nie musisz zapisywa tego obiektu do pliku — moesz skorzysta z ByteArrayOutputStream i zapisa dane do tablicy bajtów.

toByteArray()). double s. } public String getName() { return name. } catch (Exception e) { return null. day).readObject(). Object ret = in. int year. hireDay = calendar. out. out. return ret. // wczytuje klon obiektu z tablicy bajtów ByteArrayInputStream bin = new ByteArrayInputStream(bout. */ class Employee extends SerialCloneable { public Employee(String n. month .close().getName() . } } } /** Znana ju klasa Employee. GregorianCalendar calendar = new GregorianCalendar(year. } public Date getHireDay() { return hireDay. } public double getSalary() { return salary.getTime(). } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100.writeObject(this). int day) { name = n. ObjectInputStream in = new ObjectInputStream(bin).1. } public String toString() { return getClass(). salary += raise.close(). tym razem jako pochodna klasy SerialCloneable. int month. Techniki zaawansowane ObjectOutputStream out = new ObjectOutputStream(bout).74 Java. in. salary = s.

Poniewa znak \ w acuchach na platformie Java jest traktowany jako pocztek sekwencji specjalnej.Rozdzia 1. jeli nie zastosujemy w tym celu odpowiedniej metody macierzystej. musimy pamita . e opisany sposób klonowania. . C:/Windows/win. znajdujcego si w biecym katalogu (biecym katalogiem jest katalog. nie moemy ukry go samemu. w którym program jest uruchamiany). aby w ciekach dostpu do plików systemu Windows uywa sekwencji \\ (np. Jednake nie zalecamy tego rozwizania — zachowanie funkcji systemu Windows moe si zmienia . + + + + Q Strumienie i pliki 75 "[name=" + name ". } private String name. zwykle okae si znacznie wolniejszy ni metoda clone jawnie tworzca nowy obiekt i kopiujca lub klonujca pola danych. ale mimo i moemy równie sprawdzi . jakkolwiek sprytny. } Naley jednak by wiadomym. Na przykad. natomiast klasa File interesuje si sposobem przechowywania pliku na dysku. a inne systemy operacyjne mog uywa jeszcze innych separatorów. Najprostszy konstruktor obiektu File pobiera pen nazw pliku.txt"). Na przykad. private double salary.ini). w systemie Windows moemy sprawdzi (lub zmieni ) flag „tylko do odczytu” dla danego pliku.separator. oraz usun lub zmieni nazw tego pliku. C:\\Windows\\win.salary=" + salary ". czy plik jest ukryty. Jednake obsuga plików to co wicej ni tylko operacje zapisu i odczytu. Jeeli piszemy aplikacj przenon. Jeeli nie podamy cieki dostpu. W systemie Windows moemy równie korzysta ze znaku / (np. powinnimy uywa separatora odpowiedniego dla danego systemu operacyjnego. Jak to ma czsto miejsce w jzyku Java. Java uywa biecego katalogu. klasa File przyjmuje metod najmniejszego wspólnego mianownika. tworzy obiekt pliku o podanej nazwie.ini). moemy wykorzysta klas File.hireDay=" + hireDay "]". Innymi sowy. poniewa wikszo systemów obsugi plików Windows interpretuje znaki / jako separatory cieki dostpu. Jego znak jest przechowywany jako staa File. Klasa File zawiera metody potrzebne do obsugi systemu plików na komputerze uytkownika. klasy strumieni zajmuj si zawartoci plików. kiedy nastpia ostatnia modyfikacja danego pliku. Na przykad: File p = new File("test. Zarzdzanie plikami Potrafimy ju zapisywa i wczytywa dane z pliku. aby sprawdzi . private Date hireDay.

by poinformowa . . System.6 korzysta ze wszystkich omówionych metod. jeeli dir ma warto null. dziki metodzie exists moemy sprawdzi .separator + "temp").our. konstruktor tworzy obiekt File. jakby byy plikami). czy plik o danej nazwie istnieje. obiekt File moe reprezentowa zarówno plik. Oprócz tego moemy równie posuy si istniejcym ju obiektem File. pozwala traktowa katalogi tak. public class Test { public static void main(String args[]) { File f = new File("plikktóryprawdopodobnieistnieje"). String name) tworzce obiekt typu File o podanej nazwie i katalogu okrelonym przez parametr path (jeeli path ma warto null. wywoujc konstruktor: File(File dir.mkdir(). Program zamieszczony na listingu 1. poniszy program prawie na pewno wydrukuje „false”.*. String name) gdzie obiekt File reprezentuje katalog i. aby wydrukowa struktur dowolnego katalogu przekazanego jako argument wywoania w wierszu polece (atwo mona zmieni ten program w klas zwracajc list podkatalogów do dalszego przetwarzania). czy obiekt reprezentuje katalog. moemy utworzy go przy pomocy metody mkdir: tempDir.76 Java. musimy poda konstruktorowi nazw tego katalogu: File tempDir = new File(File. Co ciekawe. e plik o podanej nazwie nie istnieje i zwraca warto logiczn. gdy utworzymy obiekt typu File. Jeeli katalog nie istnieje. Techniki zaawansowane Wywoanie tego konstruktora nie tworzy nowego pliku. korzystamy z metod isDirectory i isFile. konstruktor tworzy nowy obiekt w katalogu biecym.io. Tworzenie nowego pliku na podstawie obiektu File odbywa si przy uyciu jednego z konstruktorów klas strumieni lub metody createNewFile klasy File. Jeeli dany obiekt reprezentuje katalog. tak jak poprzednio. import java. by moe rozszerzajcej klas File.println(f. równoczenie podajc ciek dostpu do nieistniejcego pliku. Aby sprawdzi . System. Dla przykadu.out. jeeli plik o danej nazwie nie istnieje.println(f. czy operacja si udaa. czy plik.getAbsolutePath()). Dziwne — w zorientowanym obiektowo systemie moglimy si spodziewa osobnej klasy Directory. Z drugiej strony. na którym pracowali projektanci jzyka Java. jak i katalog (by moe dlatego.exists()). Metoda createNewFile tworzy nowy plik tylko pod warunkiem. metoda list() zwróci nam tablic nazw plików znajdujcych si w tym katalogu. e system operacyjny. korzystajc z katalogu biecego). } } Klasa File posiada jeszcze dwa inne konstruktory: File(String path. Aby obiekt reprezentowa katalog.

// wywietla wszystkie pliki w katalogu for (int i = 0.. // rozpoczyna od katalogu nadrzdnego if (args. // jeli kolejny katalog. które speniaj warunki postawione przez interfejs FilenameFilter. Oto przykad prostej klasy implementujcej FilenameFilter.java import java.printStackTrace()." }. String[] fileNames = pathName. moemy uy obiektu klasy FileNameFilter jako parametru metody list. } } } Zamiast otrzymywa list wszystkich plików w danym katalogu.io. która akceptuje wycznie pliki o okrelonym rozszerzeniu: public class ExtensionFilter implements FilenameFilter { public ExtensionFilter(String ext) .6.00 05 Sep 1997 * @author Gary Cornell */ public class FindDirectories { public static void main(String[] args) { // jeli brak parametru wywoania. } } } catch (IOException e) { e. // wywouje rekurencyjnie metod main if (f.println(f.list().*.length.isDirectory()) { System. FindDirectories. Aby zaimplementowa interfejs FilenameFilter.length == 0) args = new String[] { ".getPath() }). aby zmniejszy rozmiar wynikowej listy plików. i++) { File f = new File(pathName. Na list bd wtedy wpisywane tylko te obiekty.out.getCanonicalPath()). try { File pathName = new File(args[0]).getPath(). Q Strumienie i pliki 77 Listing 1. main(new String[] { f.Rozdzia 1. i < fileNames. /** * @version 1. klasa musi zdefiniowa metod o nazwie accept. fileNames[i]).

dlatego nie polecamy tego sposobu.endsWith(extension). W takim przypadku warto skorzysta z metody getCanonicalPath — zamienia ona znaki / na znaki \. } public boolean accept(File dir. okazuje si. Ponisze notki API opisuj (naszym zdaniem) najwaniejsze sporód pozostaych metod klasy File. sposób ich uycia powinien by oczywisty. jeeli skorzystamy z drugiej wersji konstruktora File: File foo = new File("Documents".File 1. .txt"). Lepszym pomysem jest wykorzystanie informacji o uywanym separatorze. uywasmy znaków / jako separatorów katalogów. Techniki zaawansowane { extension = ". Java automatycznie wstawi odpowiednie separatory. czy na pliku mog by wykonywane operacje odczytu i zapisu oraz czy plik moe by wykonywany. w rodowisku Unix znak /).0 Q boolean canRead() Q boolean canWrite() Q boolean canExecute() 6 sprawdza. Jeeli tworzc obiekt klasy File. ale inne systemy mog na to nie pozwoli . e nawet w systemie Windows moesz uywa znaku / jako separatora katalogów (mimo i jest to separator systemu Unix). java.io.78 Java. przechowywanej przez statyczne pole skadowe separator klasy File (w rodowisku Windows bdzie to znak \. } W przypadku programów przenonych wyspecyfikowanie nazwy pliku znajdujcego si w okrelonym katalogu jest znacznie trudniejsze.txt") Oczywicie. metoda getAbsolutePath zwróci ciek dostpu równie zawierajc znaki /.separator + "data. co w systemie Windows bdzie wyglda do dziwnie. } private String extension. "data." + ext. Na przykad: File foo = new File("Documents" + File. String name) { return name. Jak ju o tym wspominalimy.

Oznacza to. Q boolean exists() zwraca true. Q File getCanonicalFile() 1. Q Strumienie i pliki Q boolean setReadable(boolean state. plik jest tworzony w biecym katalogu roboczym. boolean ownerOnly) 6 Q boolean setWritable(boolean state.". Jeeli ma warto null. Q boolean delete() próbuje skasowa plik. boolean ownerOnly) 6 Q boolean setExecutable(boolean state. W przeciwnym razie dotyczy wszystkich uytkowników.Rozdzia 1. jeeli dany plik lub katalog istnieje.2 Q static boolean createTempFile(String prefix. uywany jest odpowiedni separator katalogów oraz zalena od systemu operacyjnego obsuga wielkich i maych liter. gdy zostanie wyczona maszyna wirtualna. Q String getCanonicalPath() zwraca acuch zawierajcy kanoniczn form cieki dostpu. File directory) 1. Q static boolean createTempFile(String prefi. e usuwane s zbdne katalogi ". uywajc przedrostka i przyrostka do utworzenia tymczasowej nazwy. String sufix) 1.2 tworzy tymczasowy plik w domylnym katalogu tymczasowym systemu operacyjnego lub w katalogu podanym przez uytkownika. Oznacza to. boolean ownerOnly) 6 nadaje plikowi odpowiedni waciwo . 79 . jeeli plik zosta skasowany. zwraca true. w którym plik ma si znajdowa . uywane jest rozszerzenie .tmp. Metoda ta zwraca warto true. uywany jest odpowiedni separator katalogów oraz zalena od systemu operacyjnego obsuga wielkich i maych liter.2 zwraca obiekt klasy File zawierajcy kanoniczn ciek dostpu do danego pliku. w przeciwnym wypadku zwraca false. Wskazówka: zamiast tej funkcji lepiej korzysta z getCanonicalPath. Jeli parametr ownerOnly ma warto true. String sufix. w przeciwnym wypadku zwraca false. aby plik zosta skasowany. Q String getAbsolutePath() zwraca acuch zawierajcy absolutn ciek dostpu. e usuwane s zbdne katalogi ". jeli operacja nadania waciwoci powioda si.". to waciwo ta jest dostpna jedynie dla waciciela pliku. directory katalog. Q void deleteOnExit() da. Jeeli ma warto null. Parametry: prefix acuch przedrostka o dugoci co najmniej trzech znaków. sufix opcjonalny przyrostek.

Q String getParent() zwraca acuch zawierajcy nazw katalogu.2 zwraca obiekt klasy File „rodzica” danego pliku. Q long length() zwraca dugo pliku w bajtach lub 0. Q long lastModified() zwraca dat ostatniej modyfikacji pliku (liczba milisekund od pónocy 1 stycznia 1970 GMT) lub 0. jeeli katalog bazowy nie istnieje. uywamy konstruktora Date(long). lub null. W notce o getParent znajdziesz definicj „rodzica”. jego „rodzicem” jest jego katalog bazowy lub null. jeeli plik nie istnieje. . jeeli obiekt reprezentuje plik — pozostae opcje to katalog lub urzdzenie. zawierajcych nazwy plików i katalogów znajdujcych si w danym obiekcie File. Q boolean isFile() zwraca true. Techniki zaawansowane Q String getName() zwraca acuch zawierajcy nazw pliku danego obiektu File (acuch ten nie zawiera cieki dostpu). znajdujcych si w danym obiekcie i speniajcych warunki filtra. Parametry: filter uywany obiekt typu FilenameFilter. Q String[] list(FilenameFilter filter) zwraca tablic nazw plików i katalogów. Q boolean isDirectory() zwraca true. lub null. Q String[] list() zwraca tablic acuchów.2 zwraca tablic obiektów klasy File. Jeeli obiekt jest plikiem. Q File getParentFile() 1. Q File[] listFiles() 1. jeeli dany obiekt nie reprezentuje katalogu. „rodzicem” jest po prostu katalog.2 zwraca true. w którym dany plik si znajduje. w przeciwnym wypadku zwraca false. Aby zmieni t warto w obiekt Date. jeeli obiekt reprezentuje plik lub katalog ukryty. lub null. Jeeli obiekt jest katalogiem. Q String getPath() zwraca acuch zawierajcy ciek dostpu do pliku. jeeli nie ma takich elementów.80 Java. Q boolean isHidden() 1. jeeli dany obiekt nie reprezentuje katalogu. w którym znajduje si „rodzic” danego obiektu File. odpowiadajcych plikom i katalogom znajdujcym si w danym obiekcie klasy File. jeeli plik nie istnieje. jeeli obiekt reprezentuje katalog.

2 zmienia tryb pliku na „tylko do odczytu”. jakie Parametry: time upyny od pónocy 1 stycznia 1970 GMT. jeeli udao si utworzy katalog. automatycznie tworzy taki plik. Parametry: filter uywany obiekt typu FilenameFilter. jeeli którykolwiek z wymaganych katalogów nie móg zosta utworzony. w systemie Unix otrzymasz po prostu "/").2 jeeli plik o nazwie podanej przez obiekt pliku nie istnieje. Q boolean mkdir() tworzy podkatalog. w przeciwnym wypadku zwraca false. jak i mapowane dyski sieciowe. w przeciwnym wypadku zwraca false. w przeciwnym wypadku zwraca false. Q boolean setLastModified(long time) 1. Oznacza to. Zwraca true.2 okrela dat ostatniej modyfikacji pliku. lub null. Zwraca false. Q Q Strumienie i pliki File[] listFiles(FilenameFilter filter) 1. Q boolean createNewFile() 1. Jeeli udao si utworzy nowy plik. Q long getTotalSpace() 6 Q long getFreeSpace() 6 81 . liczba typu long reprezentujca ilo milisekund. e sprawdzanie nazwy oraz tworzenie nowego pliku nie zostanie zakócone przez inn dziaalno systemu. odpowiadajcych plikom i katalogom znajdujcym si w danym obiekcie klasy File i speniajcym warunki filtra. Zwraca true. jeeli nazwa zostaa zmieniona. Q URL toURL() 1. Metoda getTime klasy Date pozwala obliczy t warto .2 zwraca tablic obiektów klasy File.2 zwraca tablic obiektów klasy File odpowiadajc dostpnym katalogom najwyszego poziomu (np. ta metoda tworzy równie wymagane katalogi porednie. jeeli operacja si powioda. Q boolean mkdirs() w przeciwiestwie do mkdir. Q static File[] listRoots() 1. Q boolean setReadOnly() 1. jeeli nie ma takich elementów. którego nazwa zostaa podana przez obiekt pliku.Rozdzia 1. w przeciwnym wypadku zwraca false. Zwraca true.2 konwertuje obiekt klasy File na plik URL. w systemie Windows otrzymasz obiekty klasy File reprezentujce zainstalowane dyski — zarówno dyski lokalne. metoda zwraca true. jeeli zmiana si powioda. Q boolean renameTo(File newName) zwraca true. Parametry: newName obiekt klasy File okrelajcy now nazw pliku.

metoda ta zwraca warto 0.0 Q boolean accept(File dir. który oblicza sum kontroln CRC32 dla pliku. Q nieblokujce operacje wejcia i wyjcia. Jeli obiekt klasy File nie reprezentuje partycji. a take pliku mapowanego w pamici. jeeli dany plik spenia warunki filtra. uywajc standardowych operacji wejcia i wyjcia.4 udostpnia w pakiecie java.82 Java. Nieblokujce operacje wejcia i wyjcia zostan omówione w rozdziale 3. liczb nieprzydzielonych bajtów i liczb dostpnych bajtów partycji reprezentowanej przez obiekt klasy File. w którym znajduje si dany plik. Q pliki mapowane w pamici. Ulepszona obsuga wejcia i wyjcia Java SE 1. Kodowanie i dekodowanie znaków omówilimy ju w punkcie „Zbiory znaków” na stronie 35. Dostp do pliku odbywa si wtedy znacznie szybciej ni w tradycyjny sposób. W nastpnych podrozdziaach zajmiemy si zatem omówieniem mapowania plików w pamici oraz blokowaniem plików.FilenameFilter 1. aby zwracaa true. Techniki zaawansowane Q long getUsableSpace() 6 zwraca cakowity rozmiar. Na kocu tego podrozdziau zamiecilimy program. Mapowanie plików w pamici Wikszo systemów operacyjnych oferuje moliwo wykorzystania pamici wirtualnej do stworzenia „mapy” pliku lub jego fragmentu w pamici.nio szereg nowych rozwiza poprawiajcych obsug wejcia i wyjcia w programach.. .6 dla pliku rt. java. poniewa maj one szczególne znaczenie w przypadku komunikacji w sieci.jar (37 MB) znajdujcego si w katalogu jre/lib pakietu JDK. Q blokowanie dostpu do plików. String name) powinna zosta tak zdefiniowana. Wspomniany pakiet obsuguje nastpujce rozwizania: Q kodery i dekodery zbiorów znaków. Na jednej i tej samej maszynie otrzymalimy wyniki jego dziaania przedstawione w tabeli 1. Parametry: dir obiekt typu File reprezentujcy katalog. name nazwa danego pliku.io.

. ale atwo domyli si.READ_WRITE: otrzymany bufor umoliwia zapis danych. na naszym komputerze mapowanie pliku dao nieco lepszy wynik ni zastosowanie buforowanego wejcia i znacznie lepszy ni uycie klasy RandomAccessFile. Jakakolwiek próba zapisu do bufora spowoduje wyrzucenie wyjtku ReadOnlyBufferException. Poniej podajemy przepis na jego zastosowanie. pozwalajc na korzystanie z takich moliwoci systemów operacyjnych jak mapowanie plików w pamici.MapMode.READ_ONLY: otrzymany bufor umoliwia wycznie odczyt danych.2 sekundy Jak atwo zauway . Najpierw musimy uzyska kana dostpu do pliku. wywoujc metod map klasy FileChannel. Czasy wykonywania operacji na pliku Metoda Czas Zwyky strumie wejciowy 110 sekund Buforowany strumie wejciowy 9. Q FileChannel. blokowanie plików czy szybki transfer danych pomidzy plikami.getChannel(). które w pewnym momencie zostan równie zaktualizowane w pliku dyskowym. e w przypadku swobodnego dostpu do pliku zastosowanie mapowania da zawsze popraw efektywnoci dziaania programu. Nastpnie uzyskujemy z kanau obiekt klasy MappedByteBuffer. moemy czyta i zapisywa dane. Gdy mamy ju bufor.Rozdzia 1. Okrelamy przy tym interesujcy nas obszar pliku oraz tryb mapowania. . Oczywicie dokadne wartoci pomiarów bd si znacznie róni dla innych komputerów.). Q Strumienie i pliki 83 Tabela 1. FileOutputStream i RandomAccessFile. Naley pamita .nio znakomicie upraszcza stosowanie mapowania plików. e modyfikacje mog nie by od razu widoczne dla innych programów. Natomiast w przypadku sekwencyjnego odczytu plików o umiarkowanej wielkoci zastosowanie mapowania nie ma sensu. Dostpne s trzy tryby mapowania: Q FileChannel.PRIVATE: otrzymany bufor umoliwia zapis danych. ale wprowadzone w ten sposób modyfikacje pozostaj lokalne i nie s propagowane do pliku dyskowego. Q FileChannel. FileChannel channel = in. Kana jest abstrakcj stworzon dla plików dyskowych. wywoujc metod getChannel dodan do klas FileInputStream.9 sekundy Plik o swobodnym dostpie 162 sekundy Mapa pliku w pamici 7.MapMode. Dokadny sposób dziaania równolegego mapowania tego samego pliku przez wiele programów zaley od systemu operacyjnego. FileInputStream in = new FileInputStream(. Pakiet java. stosujc w tym celu metody klasy ByteBuffer i jej klasy bazowej Buffer. które mapuj ten sam plik.MapMode.6. . Kana uzyskujemy.

order(ByteOrder.LITTLE_ENDIAN).limit(). stosujc metody: get(byte[] bytes) get(byte[]. . Uszkodzenie zawartoci pliku powo- . Techniki zaawansowane Bufory obsuguj zarówno dostp sekwencyjny. . to wystarczy zastosowa ponisze wywoanie: buffer. jak i swobodny. . } Alternatywnie moemy równie wykorzysta dostp swobodny: for (int i = 0. Aby pozna biecy sposób uporzdkowania bajtów w buforze. Pozycja w buforze zmienia si na skutek wykonywania operacji get i put.84 Java. Jeli musimy przetworzy plik. int length) Dostpne s równie ponisze metody: getInt getLong getShort getChar getFloat getDouble umoliwiajce odczyt wartoci typów podstawowych zapisanych w pliku w postaci binarnej. i++) { byte b = buffer. i < buffer. } Moemy take czyta tablice bajtów. Jak ju wyjanilimy wczeniej. Wszystkie bajty bufora moemy przejrze sekwencyjnie na przykad w poniszy sposób: while (buffer. Suma taka jest czsto uywana do kontroli naruszenia zawartoci pliku. poczwszy od najbardziej znaczcego bajta.7 oblicza sum kontroln CRC32 pliku. Aby zapisa wartoci typów podstawowych w buforze. int offset. . który zawiera dane zapisane od najmniej znaczcego bajta. Java zapisuje dane w postaci binarnej.get(). . uywamy poniszych metod: putInt putLong putShort putChar putFloat putDouble Program przedstawiony na listingu 1.get(i). wywoujemy: ByteOrder b = buffer.hasRemaining()) { byte b = buffer. .order() Ta para metod nie stosuje konwencji nazw set/get.

zip.util.Rozdzia 1.*. return crc. CRC32 crc = new CRC32(). java. long length = file. CRC32 crc = new CRC32(). int c.read()) != -1) crc.update(c). Pakiet java.*. CRC32 crc = new CRC32(). . * Uruchamianie: java NIOTest nazwapliku * @version 1. int c.getValue(). java.read()) != -1) crc.update(nastpny bajt) long checksum = crc.*.seek(p).zip zawiera klas CRC32 pozwalajc wyznaczy sum kontroln sekwencji bajtów przy zastosowaniu nastpujcej ptli: CRC32 crc = new CRC32().nio.channels. int c = file. } public static long checksumBufferedInputStream(String filename) throws ´IOException { InputStream in = new BufferedInputStream(new FileInputStream(filename)).io.readByte(). for (long p = 0.length(). "r").nio. Q Strumienie i pliki 85 duje zwykle zmian wartoci jego sumy kontrolnej. while ((c = in. while ((c = in. while (wicej bajtów) crc. p < length.util. return crc.update(c). Listing 1.getValue(). /** * Program obliczajcy sum kontroln CRC pliku.getValue(). NIOTest.01 2004-05-11 * @author Cay Horstmann */ public class NIOTest { public static long checksumInputStream(String filename) throws IOException { InputStream in = new FileInputStream(filename).7. } public static long checksumRandomAccessFile(String filename) throws IOException { RandomAccessFile file = new RandomAccessFile(filename. p++) { file.java import import import import java.*. java.

toHexString(crcValue)). Techniki zaawansowane crc.println((end . System.out.toHexString(crcValue)).out. System. p < length.start) + " milliseconds").toHexString(crcValue)).out. long end = System. 0.out.getValue(). System. System. System.println(Long.currentTimeMillis().out. } } . FileChannel channel = in. long crcValue = checksumInputStream(args[0]). crcValue = checksumBufferedInputStream(args[0]). start = System. start = System.println((end .println("Buffered Input Stream:").println((end .start) + " milliseconds"). System. start = System.currentTimeMillis().println((end .println("Mapped File:").size(). } return crc. ´length).getChannel().update(c). CRC32 crc = new CRC32().println(Long.println(Long. crcValue = checksumRandomAccessFile(args[0]). } public static void main(String[] args) throws IOException { System. end = System. System.currentTimeMillis().MapMode.out.out.println("Input Stream:"). System.toHexString(crcValue)).out. crcValue = checksumMappedFile(args[0]).get(p).println(Long.out. end = System. for (int p = 0. long start = System.out.out.println("Random Access File:").currentTimeMillis().start) + " milliseconds").86 Java. System.currentTimeMillis(). end = System. System.start) + " milliseconds").getValue(). p++) { int c = buffer.currentTimeMillis().currentTimeMillis(). crc.currentTimeMillis().update(c).READ_ONLY. } return crc. MappedByteBuffer buffer = channel. System.map(FileChannel. int length = (int) channel.out. } public static long checksumMappedFile(String filename) throws IOException { FileInputStream in = new FileInputStream(filename).

java. Stosujemy j jedynie jako przykad pewnej praktycznej operacji na pliku.4 zwraca kana dostpu do pliku. java. java.nio.com/Science/ ´CrcMath.FileOutputStream 1.MapMode mode. Program uruchamiamy w nastpujcy sposób: java NIOTest nazwapliku java. Q int limit() zwraca pozycj kocow bufora.4 Q MappedByteBuffer map(FileChannel. . jest to pierwsza pozycja.FileInputStream 1.MapMode position pocztek mapowanego fragmentu size rozmiar mapowanego fragmentu java.FileChannel 1.0 Q FileChannel getChannel() 1. Q Strumienie i pliki 87 Opis dziaania algorytmu CRC znajdziesz na stronie http://www. na której nie s ju dostpne kolejne dane bufora.Rozdzia 1.Buffer 1.0 Q FileChannel getChannel() 1. READ_WRITE lub PRIVATE Parametry: mode zdefiniowanych w klasie FileChannel.io.nio.RandomAccessFile 1.4 zwraca kana dostpu do strumienia.relisoft.0 Q FileChannel getChannel() 1. Szczegóy oblicze sumy kontrolnej CRC nie s dla nas istotne.io. jeli bieca pozycja bufora nie osigna jeszcze jego koca. long position.4 zwraca kana dostpu do strumienia.channels. jedna ze staych READ_ONLY.io. long size) tworzy w pamici map fragmentu pliku.html.4 Q boolean hasRemaining() zwraca warto true.

nio.4 Q byte get() pobiera bajt z biecej pozycji bufora i przesuwa pozycj do kolejnego bajta. int offset. Jeli w buforze nie ma wystarczajcego miejsca. Q ByteBuffer order(ByteOrder order) Q ByteOrder order() okrela lub pobiera uporzdkowanie bajtów w buforze. int offset. Char. int length) umieszcza w buforze wszystkie bajty z tablicy lub jej zakresu i przesuwa pozycj bufora o liczb umieszczonych bajtów. Jeli bufor nie zawiera wystarczajcej liczby bajtów. to nie s one w ogóle wczytywane i zostaje wyrzucony wyjtek BufferUnderflowException. Zwracaj referencj do bufora. Short. Xxx moe by typu Int.ByteBuffer 1. Long. byte b) umieszcza bajt na podanej pozycji bufora. Q ByteBuffer put(int index. int length) wypenia tablic bajtów lub jej zakres bajtami z bufora i przesuwa pozycj bufora o liczb wczytanych bajtów. Zwraca referencj do bufora. Q byte get(int index) pobiera bajt o podanym indeksie. Techniki zaawansowane java. Zwraca referencj do bufora. . Q ByteBuffer put(byte b) umieszcza bajt na biecej pozycji bufora i przesuwa pozycj do kolejnego bajta. Q ByteBuffer get(byte[] destination) Q ByteBuffer get(byte[] destination. Parametry: destination wypeniana tablica bajtów offset pocztek wypenianego zakresu length rozmiar wypenianego zakresu Q ByteBuffer put(byte[] source) Q ByteBuffer put(byte[] source. Float lub Double. to nie s zapisywane adne bajty i zostaje wyrzucony wyjtek BufferOverflowException.88 Java. Wartoci parametru order jest staa BIG_ENDIAN lub LITTLE_ENDIAN zdefiniowana w klasie ByteOrder. xxx value) pobiera lub zapisuje warto typu podstawowego. Parametry: source tablica stanowica ródo bajtów zapisywanych w buforze offset pocztek zakresu róda length rozmiar zakresu róda Q Xxx getXxx() Q Xxx getXxx(int index) Q ByteBuffer putXxx(xxx value) Q ByteBuffer putXxx(int index.

Jeli chcemy ponownie odczyta bufor. Q Strumienie i pliki 89 Struktura bufora danych Gdy uywamy mapowania plików w pamici.11 pokazalimy. Na rysunku 1. LongBuffer i ShortBuffer. IntBuffer. DoubleBuffer. Metoda flip przenosi granic bufora do biecej pozycji. FloatBuffer. metoda ta przywraca pozycji warto 0.11. Q granic. Gdy dane skocz si lub wypeniony zostanie cay bufor. Jak atwo si domyli . Wicej szczegóów na ten temat w opisie metod zamieszczonym poniej. uywamy metody rewind lub metod mark/reset. potem odczyt”.Rozdzia 1. Na pocztku pozycja bufora jest równa 0. Bufor jest w rzeczywistoci tablic wartoci tego samego typu. . CharBuffer. która nigdy nie ulega zmianie. Teraz moemy wywoywa metod get. Q pozycj wskazujc nastpn warto do odczytu lub zapisu. Bufor Wymienione wartoci speniaj nastpujcy warunek: 0 d znacznik d pozycja d granica d pojemno Podstawowa zasada funkcjonowania bufora brzmi: „najpierw zapis. Abstrakcyjna klasa Buffer posiada klasy pochodne ByteBuffer. tworzymy pojedynczy bufor zawierajcy cay plik lub interesujcy nas fragment pliku. e bufor jest scharakteryzowany przez: Q pojemno. Buforów moemy równie uywa podczas odczytu i zapisu mniejszych porcji danych. Rysunek 1. Q opcjonalny znacznik dla powtarzajcych si operacji odczytu lub zapisu. W praktyce najczciej uywane s klasy ByteBuffer i CharBuffer. Klasa StringBuffer nie jest zwizana z omawian tutaj hierarchi klas. aby przygotowa bufor do nastpnego cyklu zapisu. Nastpnie bufor jest wypeniany danymi za pomoc metody put. a granicy nadaje warto pojemnoci bufora. Po wczytaniu wszystkich wartoci z bufora wywoujemy metod clear. poza któr odczyt i zapis nie maj sensu. pora przej do operacji odczytu. a granic jest jego pojemno . a nastpnie zeruje pozycj. W tym podrozdziale omówimy krótko podstawowe operacje na obiektach typu Buffer. dopóki metoda remaining zwraca warto wiksz od zera (metoda ta zwraca rónic granica – pozycja).

90

Java. Techniki zaawansowane
java.nio.Buffer 1.4
Q

Buffer clear()

przygotowuje bufor do zapisu, nadajc pozycji warto 0, a granicy warto równ
pojemnoci bufora; zwraca this.
Q

Buffer flip()

przygotowuje bufor do zapisu, nadajc granicy warto równ pozycji, a nastpnie
zerujc warto pozycji; zwraca this.
Q

Buffer rewind()

przygotowuje bufor do ponownego odczytu tych samych wartoci, nadajc pozycji
warto 0 i pozostawiajc warto granicy bez zmian; zwraca this.
Q

Buffer mark()

nadaje znacznikowi warto pozycji; zwraca this.
Q

Buffer reset()

nadaje pozycji bufora warto znacznika, umoliwiajc w ten sposób ponowny
odczyt lub zapis danych; zwraca this.
Q

int remaining()

zwraca liczb wartoci pozostajcych do odczytu lub zapisu; jest to rónica pomidzy
wartoci granicy i pozycji.
Q

int position()

zwraca pozycj bufora.
Q

int capacity()

zwraca pojemno bufora.
java.nio.CharBuffer 1.4
Q

char get()

Q

CharBuffer get(char[] destination)

Q

CharBuffer get(char[] destination, int offset, int length)

zwraca jedn warto typu char lub zakres wartoci typu char, poczwszy od biecej
pozycji bufora, która w efekcie zostaje przesunita za ostatni wczytan warto .
Ostatnie dwie wersje zwracaj this.
Q

CharBuffer put(char c)

Q

CharBuffer put(char[] source)

Q

CharBuffer put(char[] source, int offset, int length)

Q

CharBuffer put(String source)

Q

CharBuffer put(CharBuffer source)

zapisuje w buforze jedn warto typu char lub zakres wartoci typu char,
poczwszy od biecej pozycji bufora, która w efekcie zostaje przesunita
za ostatni zapisan warto . Wszystkie wersje zwracaj this.

Rozdzia 1.
Q

Q

Strumienie i pliki

91

CharBuffer read(CharBuffer destination)

pobiera wartoci typu char z bufora i umieszcza je w buforze destination,
do momentu a zostanie osignita granica bufora destination. Zwraca this.

Blokowanie plików
Rozwamy sytuacj, w której wiele równoczenie wykonywanych programów musi zmodyfikowa ten sam plik. Jeli pomidzy programami nie bdzie mie miejsca pewien rodzaj
komunikacji, to bardzo prawdopodobne jest, e plik zostanie uszkodzony.
Blokady plików pozwalaj kontrolowa dostp do plików lub pewnego zakresu bajtów w pliku.
Jednak implementacja blokad plików róni si istotnie w poszczególnych systemach operacyjnych i dlatego wczeniejsze wersje JDK nie umoliwiay stosowania takich blokad.
Blokowanie plików nie jest wcale tak powszechne w przypadku typowych aplikacji. Wiele
z nich przechowuje swoje dane w bazach danych, które dysponuj mechanizmami pozwalajcymi na równolegy dostp. Jeli nasz program przechowuje dane w plikach, a problem
równolegego dostpu zaczyna zaprzta nasz uwag, to czsto atwiej bdzie wanie skorzysta z bazy danych zamiast projektowa skomplikowany system blokowania plików.
Istniej jednak sytuacje, w których blokowanie plików jest niezbdne. Zaómy na przykad, 
e nasza aplikacja zapisuje preferencje uytkownika w pliku konfiguracyjnym. Jeli uruchomi
on dwie instancje aplikacji, to moe si zdarzy , e obie bd chciay zapisa dane w pliku
konfiguracyjnym w tym samym czasie. W takiej sytuacji pierwsza instancja powinna zablokowa dostp do pliku. Gdy druga instancja natrafi na blokad, moe zaczeka na odblokowanie pliku lub po prostu pomin zapis danych.
Aby zablokowa plik, wywoujemy metod lock lub tryLock klasy FileChannel:
FileLock lock = channel.lock();

lub
FileLock lock = channel.tryLock();

Pierwsze wywoanie blokuje wykonanie programu do momentu, gdy blokada pliku bdzie
dostpna. Drugie wywoanie nie powoduje blokowania, lecz natychmiast zwraca blokad lub
warto null, jeli blokada nie jest dostpna. Plik pozostaje zablokowany do momentu zamknicia kanau lub wywoania metody release dla danej blokady.
Mona równie zablokowa dostp do fragmentu pliku za pomoc wywoania
FileLock lock(long start, long size, boolean exclusive)

lub
FileLock tryLock(long start, long size, boolean exclusive)

Parametrowi flag nadajemy warto true, aby zablokowa dostp do pliku zarówno dla operacji
odczytu, jak i zapisu. W przypadku blokady wspódzielonej parametr flag otrzymuje warto
false, co umoliwia wielu procesom odczyt pliku, zapobiegajc jednak uzyskaniu przez
którykolwiek z nich wycznej blokady pliku. Nie wszystkie systemy operacyjne obsuguj

92

Java. Techniki zaawansowane
jednak blokady wspódzielone. W takim przypadku moemy uzyska blokad wyczn, nawet
jeli dalimy jedynie blokady wspódzielonej. Metoda isShared klasy FileLock pozwala nam
dowiedzie si, któr z blokad otrzymalimy.
Jeli zablokujemy dostp do kocowego fragmentu pliku, a rozmiar pliku zwikszy
si poza granic zablokowanego fragmentu, to dostp do dodatkowego obszaru nie
bdzie zablokowany. Aby zablokowa dostp do wszystkich bajtów, naley parametrowi
size nada warto Long.MAX_VALUE.

Naley pamita , e moliwoci blokad zale w znacznej mierze od konkretnego systemu
operacyjnego. Poniej wymieniamy kilka aspektów tego zagadnienia, na które warto zwróci
szczególn uwag:
Q

W niektórych systemach blokady plików maj jedynie charakter pomocniczy.
Nawet jeli aplikacji nie uda si zdoby blokady, to moe zapisywa dane w pliku
„zablokowanym” wczeniej przez inn aplikacj.

Q

W niektórych systemach nie jest moliwe zablokowanie dostpu do mapy pliku
w pamici.

Q

Blokady plików s przydzielane na poziomie maszyny wirtualnej Java. Jeli zatem
dwa programy dziaaj na tej samej maszynie wirtualnej, to nie mog uzyska blokady
tego samego pliku. Metody lock i tryLock wyrzuc wyjtek OverlappingFile
´LockException w sytuacji, gdy maszyna wirtualna jest ju w posiadaniu blokady
danego pliku.

Q

W niektórych systemach zamknicie kanau zwalnia wszystkie blokady pliku
bdce w posiadaniu maszyny wirtualnej Java. Dlatego te naley unika wielu
kanaów dostpu do tego samego, zablokowanego pliku.

Q

Dziaanie blokad plików w sieciowych systemach plików zaley od konkretnego
systemu i dlatego naley unika stosowania blokad w takich systemach.

java.nio.channels.FileChannel 1.4
Q

FileLock lock()

uzyskuje wyczn blokad pliku. Blokuje dziaanie programu do momentu
uzyskania blokady.
Q

FileLock tryLock()

uzyskuje wyczn blokad caego pliku lub zwraca null, jeli nie moe uzyska
blokady.
Q

FileLock lock(long position, long size, boolean shared)

Q

FileLock tryLock(long position, long size, boolean shared)

uzyskuje blokad dostpu do fragmentu pliku. Pierwsza wersja blokuje dziaanie
programu do momentu uzyskania blokady, a druga zwraca natychmiast warto
null, jeli nie moe uzyska od razu blokady.
Parametry: position pocztek blokowanego fragmentu
size
rozmiar blokowanego fragmentu

oznacza dowolny znak (z wyjtkiem.Rozdzia 1. Na przykad acuch "javanese" zostanie dopasowany do naszego wyraenia regularnego. nie jest wystarczajco precyzyjny. Q Pozostaa cz acucha moe zawiera jeden lub wicej dowolnych znaków.channels. Na przykad jeden z naszych przykadowych programów odnajdywa w pliku HTML wszystkie hipercza. [0-9]. co zaley od stanu odpowiedniego znacznika). musimy dokadnie okreli znaki. Q Symbol . [A-Za-z] czy [^0-9]. Oczywicie zapis . shared Q Strumienie i pliki 93 warto true dla blokady wspódzielonej. false dla wycznej java.. Znak . Wyraenia regularne Wyraenia regularne stosujemy do okrelenia wzorców wystpujcych w acuchach znaków. a znak ^ oznacza dopenienie (wszystkie znaki oprócz podanych). musimy nieco bliej pozna ich skadni. które s dopuszczalne. tak jak znaki ava w poprzednim przykadzie.nio. "Core Java" ju nie.. by moe.+ moe zosta uzgodniony dowolny acuch znaków nastpujcej postaci: Q Pierwsz jego liter jest J lub j. gdy potrzebujemy odnale acuchy zgodne z pewnym wzorcem. Aby posugiwa si wyraeniami regularnymi. znaków koca wiersza.7 i 1.8. Q Nastpne trzy litery to ava.oznacza zakres (czyli wszystkie znaki.FileLock 1.4 Q void release() zwalnia blokad. ">.. na przykad [Jj]. Q Istnieje wiele wstpnie zdefiniowanych klas znaków. których kody Unicode le w podanych granicach). Dlatego te opis wzorca wymaga zastosowania odpowiedniej skadni. Q Wikszo znaków oznacza sam siebie. .. takich jak \d (cyfry) czy \p{Sc} (symbol waluty w Unicode). Na szczcie na pocztek wystarczy kilka do oczywistych konstrukcji. Uywamy ich najczciej wtedy. Patrz przykady w tabelach 1. wyszukujc acuchy zgodne ze wzorcem <a href= ". Specyfikujc wzorzec. Oto prosty przykad. Z wyraeniem regularnym [Jj]ava. Q Przez klas znaków rozumiemy zbiór alternatywnych znaków ujty w nawiasy kwadratowe.

] Dopenienie klasy znaków. .94 Java. \B Granica inna ni sowa. jeli znacznik DOTALL zosta ustawiony). którego warto zostaa podana w notacji szesnastkowej lub ósemkowej. \f. Granice dopasowania ^$ Pocztek. koca strony. \Z Koniec wejcia oprócz ostatniego zakoczenia wiersza. . \unnnn. Klasy znaków [C1C2. \w Znak sowa [a-zA-Z0-9_]. . Skadnia wyrae regularnych Skadnia Objanienie Znaki c Znak c. . \G Koniec poprzedniego dopasowania. . . zakresem znaków (c1-c2) lub klas znaków. . \p{nazwa} Klasa znaków o podanej nazwie (patrz tabela 1. Techniki zaawansowane Tabela 1. alertu i sekwencji sterujcej. który nie jest cyfr [^0-9]. \D Znak. \b Granica sowa. .] Dowolny ze znaków reprezentowanych przez C1C2. [^. .] Cz wspólna (przecicie) dwóch klas znaków. koniec wejcia (lub pocztek. \a. \d Cyfra [0-9].. gdzie Ci jest znakiem.8). koniec wiersza w trybie wielowierszowym).7. \n. Dowolny znak oprócz koczcego wiersz (lub dowolny znak.&&. \s Znak odstpu [ \t\n\r\f\x0B]. \t. . . \A Pocztek wejcia. \r. \cc Znak sterujcy odpowiadajcy znakowi c. \e Znaki sterujce tabulatora. \W Znak inny ni znak sowa. \xnn. Kwantyfikatory X? Opcjonalnie X. \0nn. powrotu karetki. który nie jest odstpem. \0nnn Znak o kodzie. \0n. \P{nazwa} Dopenienie klasy znaków o podanej nazwie. \z Koniec wejcia. nowego wiersza. Wstpnie zdefiniowane klasy znaków . \S Znak. [.

8. nawet kosztem ogólnego powodzenia dopasowania. pomidzy n i m razy. Grupowanie (X) Grupa. Q Strumienie i pliki 95 Tabela 1.} X{n.Rozdzia 1. bd cyfry [\p{Print}&&\P{Alnum}] ASCII Wszystkie znaki ASCII [\x00-\x7F] Cntrl Znaki sterujce ASCII [\x00-\x1F] Blank Spacja lub tabulacja [\t] Space Odstp [ \t\n\r\f\0x0B] .\E Cytat… dosownie. co najmniej n razy.) Specjalna konstrukcja — patrz opis klasy Pattern. (?. które nie nale do znaków alfanumerycznych. 1 lub wicej razy. Skadnia wyrae regularnych — cig dalszy Skadnia Objanienie X* X. po którym nastpuje dowolny acuch z Y.7.. Operacje na zbiorach XY Dowolny acuch z X.. \Q. + Powoduje dopasowanie najwikszej liczby wystpie. X+ X. X|Y Dowolny acuch z X lub Y. 0 lub wicej razy.m} X n razy. Wstpnie zdefiniowane nazwy klas znaków Nazwa klasy znaków Objanienie Lower Mae litery ASCII [a-z] Upper Due litery ASCII [A-Z] Alpha Litery alfabetu ASCII [A-Za-z] Digit Cyfry ASCII [0-9] Alnum Litery alfabetu bd cyfry ASCII [A-Za-z0-9] XDigit Cyfry szesnastkowe [0-9A-Fa-f] Print lub Graph Znaki ASCII posiadajce reprezentacj graficzn (na wydruku) [\x21-\x7E] Punct Znaki. Przyrostki kwantyfikatora ? Powoduje dopasowanie najmniejszej liczby wystpie.. Tabela 1.. \n Dopasowanie n-tej grupy. X{n} X{n. Sekwencje sterujce \c Znak c (nie moe by znakiem alfabetu).

gdzie n jest numerem grupy (numeracja rozpoczyna si od \1). Istnieje zgodno w zakresie podstawowych konstrukcji. Q Jeli X i Y s wyraeniami regularnymi.7. Na przykad acuch cab moe zosta dopasowany do wyraenia [a-z]*ab. Q Grupy pozwalaj definiowa podwyraenia. a X | Y „dowolne dopasowanie do X lub Y”. ale nie do [a-z]*+ab. oznacza znak kropki.isUpperCase() javaWhitespace Odstp. na przykad BasicLatin lub Mongolian. Q Domylnie kwantyfikator dopasowuje najwiksz moliw liczb wystpie. która gwarantuje ogólne powodzenie dopasowania. nawet jeli nie gwarantuje ono ogólnego powodzenia dopasowania). Klasy jzyka Java zwizane z przetwarzaniem wyrae regularnych uywaj skadni podobnej do zastosowanej w jzyku Perl. ale potencjalnie uytecznego wyraenia regularnego.unicode. Techniki zaawansowane Tabela 1.isLowerCase() javaUpperCase Dua litera. Wicej . które opisuje liczby cakowite zapisane dziesitnie lub szesnastkowo: [+-]?[0-9]+|0[Xx][0-9A-Fa-f]+ Niestety. Moemy nastpnie zada dopasowania do wszystkich grup lub do wybranej grupy. zgodnie z wynikiem metody Character. skadnia wyrae regularnych nie jest cakowicie ustandaryzowana. na przykad L (litera) czy Sc (symbol waluty).96 Java.org Q \ spenia rol znaku specjalnego. po którym nastpuje dowolne dopasowanie do Y”. Q ^ i $ oznaczaj odpowiednio pocztek i koniec wiersza.8. wobec czego reszta wzorca pozostanie bez dopasowania. A oto przykad nieco skomplikowanego. W pierwszym przypadku wyraenie [a-z]* dopasuje jedynie znak c. wobec czego znaki ab zostan dopasowane do reszty wzorca. Jednak wyraenie [a-z]*+ dopasuje znaki cab. Grupy ujmujemy w znaki nawiasów ( ). Q Do wyraenia regularnego X moemy stosowa kwantyfikatory X+ (raz lub wicej). ale diabe tkwi w szczegóach.isWhiteSpace() javaMirrored Ekwiwalent wyniku metody Character.unicode. zgodnie z wynikiem metody Character.isMirrored() InBlok Blok jest nazw bloku znaków Unicode z usunitymi spacjami.org Kategoria lub InKategoria Kategoria jest nazw kategorii znaków Unicode. List nazw bloków znajdziesz na stronach witryny http://www. Wstpnie zdefiniowane nazwy klas znaków — cig dalszy Nazwa klasy znaków Objanienie javaLowerCase Maa litera. Wszystkie konstrukcje tej skadni zostay przedstawione w tabeli 1. a \\ znak lewego ukonika. List nazw kategorii znajdziesz na stronach witryny http://www. X* (0 lub wicej) i X? (0 lub 1). to XY oznacza „dowolne dopasowanie do X. na przykad ([+-]?)([0-9]+). do której odwoujemy si przez \n. na przykad \. zgodnie z wynikiem metody Character. Zachowanie to moemy zmodyfikowa za pomoc przyrostka ? (dopasowanie najmniejszej liczby wystpie) i przyrostka + (dopasowanie najwikszej liczby wystpie.

. Nastpnie pobra obiekt klasy Matcher i wywoa jego metod matches: Pattern pattern = Pattern. indeks pierwszej grupy równy jest 1. Q Strumienie i pliki 97 informacji na temat skadni wyrae regularnych znajdziesz w dokumentacji klasy Pattern lub ksice Wyraenia regularne autorstwa J. a nie caego wejcia. 2001). Grupy zagniedone s uporzdkowane wedug nawiasów otwierajcych. Q MULTILINE — ^ i $ oznaczaj pocztek i koniec wiersza. w tym koca wiersza. Metoda groupCount zwraca cakowit liczb grup. Na przykad znak u. Najpierw musimy utworzy obiekt klasy Pattern na podstawie acucha opisujcego wyraenie regularne. po którym nastpuje znak ¨ (diareza). Na przykad wzorzec opisany wyraeniem ((1?[0-9]):([0-5][0-9]))[ap]m .Rozdzia 1.E. Najprostsze zastosowanie wyraenia regularnego polega na sprawdzeniu. wywoujc String group(int groupIndex) Grupa 0 oznacza cae wejcie. Jeli wyraenie regularne zawiera grupy. zostanie dopasowany do znaku ü. . Pattern. Wejcie obiektu Matcher stanowi obiekt dowolnej klasy implementujcej interfejs Char ´Sequence.matches()) . Metody: int start(int groupIndex) int end(int groupIndex) zwracaj indeks pocztkowy i kocowy podanej grupy.compile(patternString. Q UNIX_LINES — tylko '\n' jest rozpoznawany jako zakoczenie wiersza podczas dopasowywania do ^ i $ w trybie wielowierszowym. moemy skonfigurowa jeden lub wicej znaczników.matcher(input). Q CANON_EQ — bierze pod uwag kanoniczny odpowiednik znaków Unicode. oznacza wszystkie znaki. na przykad String. Domylnie dotyczy to tylko znaków US ASCII. Matcher matcher = pattern. Q DOTALL — symbol . obiekt Matcher pozwala ujawni granice grup. if (matcher. Dopasowany acuch moemy pobra .UNICODE_CASE). Oto w jaki sposób zaprogramowa taki test w jzyku Java. Q UNICODE_CASE — zastosowany w poczeniu z CASE_INSENSITIVE. Friedla (Wydawnictwo Helion. Kompilujc wzorzec. StringBuilder czy CharBuffer.CASE_INSENSITIVE + Pattern. czy dany acuch znaków pasuje do tego wyraenia. Obsugiwanych jest sze nastpujcych znaczników: Q CASE_INSENSITIVE — dopasowanie niezalenie od wielkoci liter. na przykad: Pattern pattern = Pattern.compile(patternString).F. dotyczy wszystkich znaków Unicode.

*.util. System.java import java. e obiekt klasy Matcher bdzie raportowa grupy w poniszy sposób: Indeks grupy 0 1 2 3 Pocztek 0 0 0 3 Koniec 7 5 2 5 acuch 11:59am 11:59 11 59 Program przedstawiony na listingu 1.equals("")) return.println("Enter pattern: "). Pattern pattern = null.println("Enter string to match: "). if (matcher. } while (true) { System. try { pattern = Pattern. import java.matcher(input).8 umoliwia wprowadzenie wzorca. Jeli acuch pasuje do wzorca zawierajcego grupy. System.out.8. RegExTest.out. Jeli wzorzec zawiera grupy. którego dopasowanie zostanie sprawdzone. Wprowad wzorzec i dopasowywany a cuch.01 2004-05-11 @author Cay Horstmann */ public class RegExTest { public static void main(String[] args) { Scanner in = new Scanner(System.nextLine().println("Pattern syntax error").98 Java. } catch (PatternSyntaxException e) { System.matches()) .exit(1). @version 1. Techniki zaawansowane dla danych 11:59am spowoduje. /** Program testujcy zgodno z wyraeniem regularnym. a nastpnie acucha. na przykad: ((11):(59))am Listing 1.nextLine(). String input = in. if (input == null || input. Matcher matcher = pattern.compile(patternString).*. String patternString = in. to program wywietla granice grup w postaci nawiasów. program wywietli ich granice po uzgodnieniu a cucha ze wzorcem.util.out.regex.in).

groupCount(). j++) if (i == matcher. import java.. na przykad: java HrefMatch http://www.Rozdzia 1.horstmann. i++) { for (int j = 1.regex.length().print(input.substring(start. int end = matcher. Aby znale kolejne dopasowanie. } Program przedstawiony na listingu 1.01 2004-06-04 * @author Cay Horstmann */ .util..out. /** * Program wywietlajcy wszystkie adresy URL na stronie WWW * poprzez dopasowanie wyraenia regularnego * opisujcego znacznik <a href=. } } else System.out.end().*. lecz jedynie odnale jeden lub wicej podacuchów.com Listing 1. String match = input. j <= g.io. .9. end).*.start().out. if (g > 0) { for (int i = 0. j++) if (i + 1 == matcher. j <= g. i < input. } } } Zwykle nie chcemy dopasowywa do wzorca caego acucha wejciowego.> jzyka HTML.println("No match"). Jeli zwróci ona warto true. Uruchamiajc program.charAt(i)). * Uruchamianie: java HrefMatch adresURL * @version 1.find()) { int start = matcher.println().print(')').out. while (matcher.print('('). int g = matcher. Q Strumienie i pliki 99 { System.out. HrefMatch.println("Match"). Odnajduje on wszystkie hipercza na stronie internetowej i wywietla je.net.*.out. . import java. uywamy metody find klasy Matcher.start(j)) System.java import java. } System. . System. to stosujemy metody start i end w celu odnalezienia dopasowanego podacucha. podajemy adres URL jako parametr w wierszu polece.end(j)) System.9 wykorzystuje powyszy mechanizm. for (int j = 1.

CASE_INSENSITIVE).append((char) ch). Na przykad poniszy kod zastpi wszystkie sekwencje cyfr znakiem #: Pattern pattern = Pattern.com". String output = matcher. // poszukuje wszystkich wystpie wzorca String patternString = "<a\\s+href\\s*=\\s*(\"[^\"]*\"|[^\\s>])\\s*>". System.printStackTrace(). } } catch (IOException e) { e. Pattern.matcher(input). int end = matcher. // wczytuje zawarto do obiektu klasy StringBuilder StringBuilder input = new StringBuilder().out.substring(start.println(match).compile(patternString.matcher(input). Matcher matcher = pattern.printStackTrace(). . else urlString = "http://java.end(). Matcher matcher = pattern.100 Java. } catch (PatternSyntaxException e) { e. String match = input. } } } Metoda replaceAll klasy Matcher zastpuje wszystkie wystpienia wyraenia regularnego podanym acuchem.replaceAll("#").start().find()) { int start = matcher.compile("[0-9]+").sun.read()) != -1) input. while (matcher. // otwiera InputStreamReader dla podanego URL InputStreamReader in = new InputStreamReader(new ´URL(urlString).openStream()). end). Pattern pattern = Pattern. Techniki zaawansowane public class HrefMatch { public static void main(String[] args) { try { // pobiera URL z wiersza polece lub uywa domylnego String urlString. int ch. while ((ch = in.length > 0) urlString = args[0]. if (args.

Sekwencja \$ pozwala umieci znak $ w zastpujcym tekcie. Metoda replaceFirst zastpuje jedynie pierwsze wystpienie wzorca.acuch zastpujcy moe zawiera referencje grup wzorca: $n zostaje zastpione przez n-t grup. .

Jeli limit jest równy lub mniejszy od 0.split(input). Jeli dopasowanych zostao limit . Q String[] split(CharSequence input) Q String[] split(CharSequence input. Q Matcher matcher(CharSequence input) tworzy obiekt pozwalajcy odnajdywa dopasowania do wzorca w acuchu wejciowym. jeli acuch wejciowy pasuje do wzorca.compile("\\s*\\p{Punct}\\s*"). UNIX_LINES.4 Q static Pattern compile(String expression) Q static Pattern compile(String expression.Pattern 1. jeli pocztek acucha wejciowego pasuje do wzorca.util. int limit) rozbija acuch wejciowy na tokeny.4 Q boolean matches() zwraca true. Pattern pattern = Pattern. to ostatni element zwracanej tablicy zawiera niepodzielon reszt acucha wejciowego. Q Strumienie i pliki 101 Klasa Pattern dysponuje równie metod split. Jeli limit jest równy 0. MULTILINE. Na przykad poniszy kod podzieli acuch wejciowy na tokeny na podstawie znaków interpunkcyjnych otoczonych opcjonalnym odstpem. Q boolean find() . DOTALL i CANON_EQ. Parametry: expression wyraenie regularne flags jeden lub wicej znaczników CASE_INSENSITIVE.Matcher 1.util. Parametry: input acuch rozbijany na tokeny limit maksymalna liczba utworzonych acuchów.regex. int flags) kompiluje acuch wyraenia regularnego. która dzieli acuch wejciowy na tablic acuchów. Q boolean lookingAt() zwraca true. Zwraca tablic tokenów. które nie zawieraj granic podziau. stosujc wzorzec do okrelenia granic podziau. uywajc dopasowa wyraenia regularnego jako granic podziau. UNICODE_CASE. to puste acuchy koczce dane wejciowe nie s umieszczane w tablicy java.1 granic podziau. String[] tokens = pattern. to zostanie podzielony cay acuch wejciowy.Rozdzia 1. tworzc obiekt wzorca przyspieszajcy przetwarzanie.regex. java.

. Parametry: groupIndex indeks grupy (wartoci indeksu rozpoczynaj si od 1) lub 0 dla oznaczenia caego dopasowania Q String replaceAll(String replacement) Q String replaceFirst(String replacement) zwracaj acuch powstay przez zastpienie podanym acuchem wszystkich dopasowa lub tylko pierwszego dopasowania. Q int groupCount() zwraca liczb grup we wzorcu wejciowym. stosujemy sekwencj \$. Parametry: replacement acuch zastpujcy moe zawiera referencje do grup wzorca postaci $n. Techniki zaawansowane Q boolean find(int start) próbuje odnale nastpne dopasowanie i zwraca true. Parametry: start indeks. jeli próba si powiedzie.nio. W tym rozdziale omówilimy metody obsugi plików i katalogów. Q Matcher reset() Q Matcher reset(CharSequence input) resetuje stan obiektu Matcher. Q String group() zwraca biece dopasowanie. jak równie szereg ulepsze. Druga wersja powoduje przejcie obiektu Matcher do pracy z innymi danymi wejciowymi. Q int start(int groupIndex) Q int end(int groupIndex) zwraca pozycj pocztkow grupy lub nastpn pozycj za grup dla danej grupy biecego dopasowania. od którego naley rozpocz poszukiwanie Q int start() Q int end() zwraca pozycj pocztkow dopasowania lub nastpn pozycj za dopasowaniem. które do obsugi wejcia i wyjcia wprowadzi pakiet java. W nastpnym rozdziale omówimy moliwoci biblioteki jzyka Java zwizane z przetwarzaniem jzyka XML. Aby umieci w ancuchu symbol $. a take metody zapisywania informacji do plików w formacie tekstowym i binarnym i wczytywania informacji z plików w formacie tekstowym i binarnym. Obie wersje zwracaj this.102 Java. Parametry: groupIndex indeks grupy (wartoci indeksu rozpoczynaj si od 1) lub 0 dla oznaczenia caego dopasowania Q String group(int groupIndex) zwraca acuch dopasowany do podanej grupy.