E N D
Strumienie • W większości języków programowania biblioteki wejścia/wyjścia ukrywają szczegóły obsługi poszczególnych mediów pod abstrakcją strumienia (ang. stream). Strumienie są używane zarówno do wysyłania/zapisywania jak i pobierania/odczytywania porcji danych. Główną zaletą takiego podejścia jest jego uniwersalność.
W Javie hierarchia strumieni oparta jest o cztery klasy: • InputStream i Reader reprezentują strumienie danych wejściowych, a OutputStream i Writer strumienie danych wyjściowych • Para InputStream i OutputStream jest przeznaczona do obsługi danych binarnych. • Readeri Writer dodano do języka w wersji 1.1 i służą do obsługi danych znakowych. InputStream, OutputStream Reader Writer.
Strumienie ujednolicają obsługę poszczególnych rodzajów mediów. Standardowe biblioteki Javy zawierają klasy reprezentujące strumienie wejściowe i wyjściowe na: • pliku, • tablicy bajtów/znaków, • obiekcie String oraz • łączu (ang. pipe) służącym do komunikacji procesów.
Konwersja między strumieniami binarnymi i znakowymi • Strumień binarny można przekształcić na strumień znakowy. Służą do tego klasy InputStreamReader i OutputStreamWriter. Taka konwersja czasami jest bardzo przydatna, np. podczas kompresji i dekompresji danych.
Wzorzec projektowy Dekorator • Wzorzec dekoratora polega na opakowaniu oryginalnej klasy w nową klasę "dekorującą". Zwykle przekazuje się oryginalny obiekt jako parametr konstruktora dekoratora, metody dekoratora wywołują metody oryginalnego obiektu i dodatkowo implementują nową funkcjonalność.
Wzorzec projektowy Dekorator – kaskadowe łączenie strumieni • Strumienie można wykorzystać jedynie w podstawowy sposób – odczytując lub zapisując poszczególne bajty lub znaki. Jeśli chcemy dodać nową funkcjonalność do strumieni, np. możliwość buforowania lub kompresji musimy nasz podstawowy egzemplarz strumienia przekazać do obiektu zwanego dekoratorem. Dekorator implementuje ten sam interfejs lub rozszerza tę samą klasę bazową, którą rozszerza dekorowany obiekt. Dzięki temu można go używać zamiast obiektu oryginalnego. Poszczególne metody dekoratora wywołują metody oryginalnego obiektu, a w między czasie dodają nową funkcjonalność.
Standardowe wejście/wyjście • W Javie do standardowego wyjścia/wejścia mamy dostęp poprzez zmienne statyczne klasy System System.out i System.err (typu PrintStream) System.in (typu InputStream)
Przekierowywanie standardowego wejścia/wyjścia • setIn(InputStream) • setOut(PrintStream) • setErr(PrintStream) Do przekierowywania używamy statycznych metod z klasy System
Nowe wejście/wyjście • W Javie 1.4 dodano "nowe" biblioteki wejścia/wyjścia (ang. new I/O). Są one zebrane w pakietach java.nio.* • Głównym celem przy opracowywaniu nowych bibliotek był wzrost prędkości działania • Jeżeli nie zależy nam na osiągnięciu maksymalnej możliwej prędkości działania wejścia/wyjścia, dotychczasowe "stare" biblioteki są nadal zalecana.
Wprowadzenie Serializacja - przekształcanie obiektów na postać binarną lub znakową (np. XML) w sposób, który umożliwia ich późniejsze odtworzenie Deserializacja – proces odwrotny Zastosowania: • Zachowywanie stanu obiektu w pliku • Przesyłanie obiektu strumieniami,np. przez sieć
Serializacja obiektu • Interfejs Serializable – wymagana jest jego implementacja, • ObjectOutputStream, ObjectInputStream - klasy umożliwiające zapis i odczyt serializowanych obiektów, • Zapis – metoda writeObject (Objecto) • Odczyt – metoda readObject (), nie wywołuje konstruktora obiektu, • Wielokrotne referencje do obiektu –tylko jeden egzemplarz zapisany
Serializacja obiektu - przykład class A implementsSerializable { public A(int n) { num = n; System.out.println("Konstruuję obiekt klasy A"); } publicStringtoString() { return "" + num; } intnum; public staticvoidmain(String[] args) { A a = new A(42);System.out.println(a); ObjectOutputStream out = newObjectOutputStream( newFileOutputStream("plik.o")); out.writeObject(a);out.close(); ObjectInputStreamin= newObjectInputStream(newFileInputStream("plik.o")); A a1 = (A) in.readObject();in.close(); System.out.println(a1); }} Wynik działania: Konstruuję obiekt klasy A 42 42
Kontrola serializacji • Składowe transient – atrybuty wyłączone z domyślnego systemu serializacji, • Metody writeObject() i readObject() – umożliwiają zastąpienie domyślnych metod serializacji własnym kodem
Transient - przykład classA implementsSerializable { intnum; transientStringstr; public A(int n, String s) {num = n; str = s;} publicStringtoString {return num + ” ” + str;} } public staticvoidmain(String[] args) { A a1 = new A (42, ”napis”), a2; System.out.println(a1); // zapis i odczyt w taki sam sposób out.writeObject(a1); a2 = (A) in.readObject(); System.out.println(a2); } Wynik działania: 42 napis 42 null
writeObject(),readObject() class A implementsSerializable { intnum; transientStringstr; public A(int n, String s) {num = n; str = s;} publicStringtoString {return num + ” ” + str;} privatevoidwriteObject(ObjectOutputStreamoos) throwsIOException{ oos.defaultWriteObject(); oos.writeObject(str); } privatevoidreadObject(ObjectInputStreamois) throwsIOException, ClassNotFoundException{ ois.defaultReadObject(); str = (String) ois.readObject(); } } Wynik działania: 42 napis 42 napis
Interfejs Externalizable • Rozszerzenie interfejsu Serializable, • Metody: readExternal(), writeExternal(), interfejs deklaruje je jako publiczne • Brak możliwości korzystania z domyślnego systemu serializacji (można jednak przesłać obiekt do metody writeObject() ) • W trakcie deserializacji wywołanie domyślnego konstruktora
Wersjonowanie • Problem: wczytanie z pliku obiektu nowszej lub starszej wersji klasy • Domyślne zachowanie Javy: zgłoszenie wyjątku InvalidClassException • Rozwiązanie: atrybutstaticfinal long serialVersionUID • Atrybuty usunięte z klasy, a zawarte w pliku są ignorowane; nowe atrybuty mają wartości domyślne dla swojego typu
Serializacja do XML • XMLEncoder, XMLDecoder – klasy z pakietu java.beans, umożliwiające zapis do XML • Serializowane obiekty powinny być zgodne ze specyfikacją JavaBeans: • Publiczna klasa, • Publiczny, bezparametrowy konstruktor, • Metody geti set dla każdego atrybutu • Implementacja interfejsu Serializable nie jest wymagana
XML- przykład Wynik działania: 42 napis 42 napis publicclass A { intnum; Stringstr; public A(){} public A(int n, String s) {num = n; str = s;} publicintgetNum() {return num;} publicvoidsetNum(int n) {num = n;} publicStringgetStr() {returnstr;} publicvoidsetStr(String s) {str = s;} publicStringtoString() {returnnum + " " + str;} public staticvoidmain(String[] args) throwsFileNotFoundException{ A a = new A(42, "napis"), a1; System.out.println(a); XMLEncoder out = newXMLEncoder(newFileOutputStream("plik.xml")); out.writeObject(a); out.close(); XMLDecoderin = newXMLDecoder(new FileInputStream("plik.xml")); a1 = (A) in.readObject(); in.close(); System.out.println(a1);}}
XML- przykład Wynikowy plik XML: <?xml version="1.0" encoding="UTF-8"?> <javaversion="1.6.0_17"class="java.beans.XMLDecoder"> <objectclass="A"> <voidproperty="num"> <int>42</int> </void> <voidproperty="str"> <string>napis</string> </void> </object> </java>