System wejścia/wyjścia
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ść.
Strumienie
1. InputStream i Reader reprezentują strumienie danych wejściowych, a OutputStream i Writer strumienie danych wyjściowych
2. Para InputStream i OutputStream jest przeznaczona do obsługi danych binarnych.
3. Reader i Writer dodano do języka w wersji 1.1 i służą do obsługi danych znakowych.
W Javie hierarchia strumieni oparta jest o cztery klasy:
1. InputStream, 2. OutputStream
1. Reader 2. Writer.
pliku, tablicy bajtów/znaków, obiekcie String oraz łączu (ang. pipe) służącym do komunikacji
procesów.
Strumienie ujednolicają obsługę poszczególnych rodzajów mediów. Standardowe biblioteki Javy zawierają klasy reprezentujące strumienie wejściowe i wyjściowe na:
Typy strumieniPodklasy InputStream i
OutputStreamPodklasy Reader i
Writer Opis
FileInputStream i FileOutputStream FileReader i FileWriter
Pozwalają odczytywać i zapisywać pliki dyskowe. Jako parametr konstruktora przekaż nazwę pliku dyskowego lub
wskazujący go obiekt File. Tworząc obiekt wyjściowy, jako drugi argument konstruktora,
możesz przekazać wartość logicznią określającą czy zamiast zamazywać
istniejący plik dopisywać kolejne dane na jego końcu.
ByteArrayInputStream i ByteArrayOutputStream
CharArrayReader i CharArrayWriter
Bufor w pamięci oparty na tablicy odpowiednio bajtów lub znaków. Tworząc obiekt wejściowy, przekaż konstruktorowi tablicę, na której ma być oparty. Tworząc obiekt wyjściowy, przekaż konstruktorowi
początkowy rozmiar bufora.
Typy strumieni
Podklasy InputStream i OutputStream
Podklasy Reader i Writer Opis
StringBufferInputStream (nie ma odpowiednika do
zapisu)
StringReader i StringWriter
Bufor w pamięci oparty na napisie String (implementacja posługuje się obiektem
StringBuffer). Tworząc obiekt wejściowy, przekaż konstruktorowi napis, na którym ma
być oparty. Tworząc obiekt wyjściowy przekaż konstruktorowi początkowy rozmiar bufora. Zaleca się używanie klas z hierarchii Reader/Writer. StringBufferInputStream jest
oznaczony jako deprecated.
PipedInputStream i PipedOutputStream
PipedReader i PipedWriter
Łącze do komunikacji między procesami. Przy pomocy konstruktora
bezparametrowego należy najpierw utworzyć obiekt jednego rodzaju (wejściowy lub
wyjściowy), a następnie przekazać go jako parametr konstruktora obiektu drugiego rodzaju (odpowiednio wyjściowego lub
wejściowego). Strumienie zostaną połączone łączem, które będzie przesyłać dane od strumienia wyjściowego do wejściowego.
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.
Konwersja między strumieniami binarnymi i znakowymi
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
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ść.
Wzorzec projektowy Dekorator – kaskadowe łączenie strumieni
Przykłądowe klasy dekorujące IO
Podklasy InputStream i OutputStream
Podklasy Reader i Writer Opis
BufferedInputStream i BufferedOutputStream
BufferedReader i BufferedWriter
Operacje na strumieniu stają się buforowane. W większości przypadków skutkuje to
znaczącym wzrostem efektywności. Zamiast wykonywać wiele drobnych operacji na
strumieniu, np. wiele razy odczytywać/zapisywać z pliku dyskowego małe porcje danych. Dekorator odczytuje większą porcję na zapas lub zapamiętuje
dane, które mają być wysłane do strumienia dopóki nie uzbiera się ich dostateczna ilość.
PrintStream PrintWriterDodają wiele nowych metod pozwalających
zapisywać do strumienia dane w sposób
czytelny dla człowieka.
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)
Standardowe wejście/wyjście
1. setIn(InputStream)2. setOut(PrintStream)3. setErr(PrintStream)
Przekierowywanie standardowego wejścia/wyjścia
Do przekierowywania używamy statycznych metod z klasy System
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.
Nowe wejście/wyjście
Serializacja
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 odwrotnyZastosowania: Zachowywanie stanu obiektu w pliku Przesyłanie obiektu strumieniami,
np. przez sieć
Wprowadzenie
Interfejs Serializable – wymagana jest jego implementacja,
ObjectOutputStream, ObjectInputStream - klasy umożliwiające zapis i odczyt serializowanych obiektów,
Zapis – metoda writeObject (Object o) Odczyt – metoda readObject (), nie
wywołuje konstruktora obiektu, Wielokrotne referencje do obiektu –
tylko jeden egzemplarz zapisany
Serializacja obiektu
class A implements Serializable {public A(int n) { num = n; System.out.println("Konstruuję obiekt klasy A"); }public String toString() { return "" + num; }int num;
public static void main(String[] args) {A a = new A(42); System.out.println(a);ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("plik.o"));out.writeObject(a); out.close();ObjectInputStream in = new ObjectInputStream(new
FileInputStream("plik.o"));A a1 = (A) in.readObject(); in.close(); System.out.println(a1); }}
Serializacja obiektu - przykład
Wynik działania:Konstruuję obiekt klasy A4242
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
Kontrola serializacji
class A implements Serializable {int num;transient String str;public A(int n, String s) {num = n; str = s;}public String toString {return num + ” ” + str;}
}
public static void main(String[] args) {A a1 = new A (42, ”napis”), a2;System.out.println(a1);// zapis i odczyt w taki sam sposóbout.writeObject(a1);a2 = (A) in.readObject();System.out.println(a2);
}
Transient - przykład
Wynik działania:42 napis42 null
class A implements Serializable {int num;transient String str;public A(int n, String s) {num = n; str = s;}public String toString {return num + ” ” + str;}
private void writeObject(ObjectOutputStream oos) throws IOException {oos.defaultWriteObject(); oos.writeObject(str);
}private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject(); str = (String) ois.readObject();}
}
writeObject(), readObject()
Wynik działania:42 napis42 napis
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
Interfejs Externalizable
Problem: wczytanie z pliku obiektu nowszej lub starszej wersji klasy
Domyślne zachowanie Javy: zgłoszenie wyjątku InvalidClassException
Rozwiązanie: atrybutstatic final long serialVersionUID
Atrybuty usunięte z klasy, a zawarte w pliku są ignorowane; nowe atrybuty mają wartości domyślne dla swojego typu
Wersjonowanie
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 get i set dla każdego atrybutu
Implementacja interfejsu Serializable nie jest wymagana
Serializacja do XML
public class A {int num;String str;public A(){}public A(int n, String s) {num = n; str = s;}public int getNum() {return num;}public void setNum(int n) {num = n;}public String getStr() {return str;}public void setStr(String s) {str = s;}public String toString() {return num + " " + str;}
public static void main(String[] args) throws FileNotFoundException{A a = new A(42, "napis"), a1; System.out.println(a);XMLEncoder out = new XMLEncoder(new FileOutputStream("plik.xml"));out.writeObject(a); out.close();
XMLDecoder in = new XMLDecoder(new FileInputStream("plik.xml"));a1 = (A) in.readObject(); in.close(); System.out.println(a1);}}
XML- przykładWynik działania:42 napis42 napis
Wynikowy plik XML:<?xml version="1.0" encoding="UTF-8"?> <java version="1.6.0_17" class="java.beans.XMLDecoder">
<object class="A"> <void property="num">
<int>42</int> </void> <void property="str">
<string>napis</string> </void>
</object> </java>
XML- przykład
Top Related