Programowanie Obiektowe
Java
Małgorzata Janik
Zakład Fizyki Jądrowej
Operacje wejścia-wyjścia
strumienie
Pakiety IO
●
Java dostarcza dwóch podstawowych pakietów (z podpakietami), służących do przeprowadzania operacji wejścia-wyjścia:
– java.io
– java.nio
●
Pakiet java.io zawiera przede wszystkim klasy, które pozwalają operować na strumieniach danych.
●
W pakiecie java.nio ("Java new input-output", w skrócie NIO)
wprowadzono dodatkowe środki wejścia-wyjścia, takie jak kanały, bufory i selektory
– Mimo nazwy ("new input-output") środki te nie zastępują klas strumieniowych.
Służą przede wszystkim do zapewnienia wysokiej efektywności i elastyczności programów, które w bardzo dużym stopniu obciążone są operacjami wejścia- wyjścia. W szczególności dotyczy to serwerów, które muszą równolegle obsługiwać ogromną liczbę połączeń sieciowych.
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Pakiety IO
Zródło: http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
●
Java dostarcza dwóch podstawowych pakietów (z podpakietami), służących do przeprowadzania operacji wejścia-wyjścia:
– java.io
– java.nio
●
Pakiet java.io zawiera przede wszystkim klasy, które pozwalają operować na strumieniach danych.
●
W pakiecie java.nio ("Java new input-output", w skrócie NIO)
wprowadzono dodatkowe środki wejścia-wyjścia, takie jak kanały, bufory i selektory
– Mimo nazwy ("new input-output") środki te nie zastępują klas strumieniowych.
Służą przede wszystkim do zapewnienia wysokiej efektywności i elastyczności programów, które w bardzo dużym stopniu obciążone są operacjami wejścia- wyjścia. W szczególności dotyczy to serwerów, które muszą równolegle obsługiwać ogromną liczbę połączeń sieciowych.
–
Stosunkowo niedawno (w Javie 7) doszedł
również pakiet NIO.2...
Image by Thalpha
Strumienie
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Strumienie
Strumień danych jest pojęciem abstrakcyjnym, logicznym.
Oznacza ciąg danych, właśnie „strumień”, do którego dane mogą być dodawane i z którego dane mogą być pobierane.
Przy czym:
● strumień związany jest ze źródłem lub odbiornikiem danych,
● źródło lub odbiornik mogą być dowolne: plik, pamięć, URL, gniazdo, potok ...
● strumień służy do zapisywania/odczytywania informacji - dowolnych danych,
● program:
– kojarzy strumień z zewnętrznym źródłem/odbiornikiem,
– otwiera strumień,
– dodaje lub pobiera dane ze strumienia,
– zamyka strumień.
● przy czytaniu lub zapisie danych z/do strumienia mogą być wykonywane dodatkowe operacje (np. buforowanie, kodowanie/dekodowanie, kompresja/dekompresja)
● w Javie dostarczono szereg klas reprezentujących strumienie; hierarchia tych klas
pozwala na programowanie w sposób abstrahujący od konkretnych źródeł i odbiorników.
Żródło: http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
Klasy strumieni
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Strumienie wejściowe / wyjściowe
Strumień wejściowy
Strumienie wejściowe / wyjściowe
Na strumieniach możemy wykonywać dwie podstawowe operacje:
●
odczytywanie danych
–
z pliku, z konsoli, z tablicy, z zewnętrznego urządzenia, z gniazda...
●
zapisywanie danych
–
do pliku, na ekran, do gniazda...
Z tego punktu widzenia możemy mówić o strumieniach wejściowych i wyjściowych.
I odpowiednio do tego – Java wprowadza dwie rozłączne hierarchie klas strumieniowych: klasy strumieni wejściowych i klasy strumieni
wyjściowych.
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Strumienie wejściowe / wyjściowe
Ilość wejściowych / wyjściowych strumieni w programie jest nieograniczona:
od 0 do N.
https://www.javatpoint.com/java-
Strumienie powiązane z konsolą
●
W Javie istnieją strumienie tworzone automatycznie – powiązane z konsolą:
–
System.out: strumień standardowego wyjścia
–
System.in: strumień stndardowego wejścia
–
System.err: strumień standardowego wyjścia błędu
●
Kod do wypisania informacji / błędu w konsoli:
●
Kod do wczytania informacji z konsoli:
System.out.println("simple message");
System.err.println("error message");
int i=System.in.read();//returns ASCII code of 1st character System.out.println((char)i);//will print the character
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Strumienie bajtowe / znakowe
●
Pobranie/zapis danych może dotyczyć określonych atomistycznych (minimalnie rozróżnialnych w trakcie operacji) „porcji danych”.
●
Mogą to być
– Bajty
– Znaki (standard w Javie to Unikod, znak Unikodu jest złożony z dwóch bajtów)
●
Wobec tego powstają kolejne dwie rozłączne hierarchie klas strumieniowych:
– klasy strumieni bajtowych („atomem” operacji we-wy jest bajt),
– klasy strumieni znakowych („atomem” są znaki Unikodu – 2 bajty).
●
Przy przetwarzaniu tekstów należy korzystać ze strumieni znakowych ze względu na to, iż w trakcie czytania/pisania wykonywane są
odpowiednie operacje kodowania/dekodowania ze względu na stronę kodową właściwą dla źródła/odbiornika
Żródło: http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
Strumienie znakowy / bajtowy
Strumień wejściowy
znakowy Strumień wejściowy
bajtowy
Nie można ich traktować tak samo…
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Wejście Wyjście
Strumień bajtowy InputStream OutputStream
Strumień znakowy Reader Writer
Rodzaje strumieni
●
Zatem w Javie mamy 4 podstawowe rodzaje strumieni:
– Wejścia / wyjścia
– Bajtowe / znakowe
Klasy strumieni
InputStream, OutputStream, Reader, Writer 4 klasy strumieni abstrakcyjnych→ 4 klasy strumieni abstrakcyjnych
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Rodzaje strumieni
Powyższe klasy strumieni to klasy abstrakcyjne, zatem bezpośrednio nie można tworzyć obiektów tych klas.
Dostarczają one natomiast podstaw dla wszystkich innych klas strumieniowych oraz paru ogólnych użytecznych (choć bardzo podstawowych) metod.
Metody te umożliwiają m.in.
● czytanie - read(..) (bajtów, znaków) - różne wersje tej (przeciążonej) metody pozwalają na
przeczytanie jednego bajtu ze strumienia bajtowego lub znaku ze strumienia znakowego albo całej porcji bajtów/znaków,
● zapisywanie - write(..) (bajtów/znaków) - różne wersje tej (przeciążonej) metody pozwalają
zapisywac pojedyńcze bajty/znaki lub tablice bajtów/znaków, a w przypadku strumieni znakowych również napisy (obiekty klasy String),
● pozycjonowanie strumieni (metody skip(..), mark(..), reset() ) - każdy strumień może być traktowany jako sekwencja bajtów/znaków, czytanie i zapisywanie zawsze dotyczy bieżącej pozycji tej
sekwencji; po wykonaniu operacji czytania lub zapisu bieżąca pozycja zwiększa się o jeden; metody pozycjonowania pozwalają zmieniać bieżącą pozycję.
● zamykanie strumieni (metoda close()) - strumień zawsze należy zamknąć po zakończeniu operacji na nim.
Metody te są zazwyczaj odpowiednio przedefiniowane w klasach dziedziczących; polimorfizm zapewnia ich oszczędne i właściwe użycie.
Wejście Wyjście
Strumień bajtowy InputStream OutputStream
Strumień znakowy Reader Writer
Przykład
●
Klasa która kopiuje strumień wejściowy do strumienia wyjściowego
– Uwaga: metoda read() zwraca liczbę całkowitą, reprezentującą kolejny znak ze
strumienia znakowego (lub bajt ze strumienia bajtowego) albo wartość -1 gdy czytanie sięga poza koniec pliku.
class Stream {
static void copy(InputStream in, OutputStream out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
}
static void copy(Reader in, Writer out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
} }
Klasy abstrakcyjne Wejście Wyjście
Strumień bajtowy InputStream OutputStream
Strumień znakowy Reader Writer
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Przykład
●
Klasa która kopiuje strumień wejściowy do strumienia wyjściowego
– Uwaga: metoda read() zwraca liczbę całkowitą, reprezentującą kolejny znak ze
strumienia znakowego (lub bajt ze strumienia bajtowego) albo wartość -1 gdy czytanie sięga poza koniec pliku.
●
Możemy teraz użyć metody copy wobec dowolnych strumieni z odpowiednich konkretnych klas hierarchii klas strumieniowych, np.
By kopiowanie miało sens input musi być powiązane z konkretnym źródłem danych, a output – konkretnym odbiornikiem danych.
class Stream {
static void copy(InputStream in, OutputStream out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
}
static void copy(Reader in, Writer out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
} }
Stream.copy(input, output);
Przykład
●
Klasa która kopiuje strumień wejściowy do strumienia wyjściowego
– Uwaga: metoda read() zwraca liczbę całkowitą, reprezentującą kolejny znak ze
strumienia znakowego (lub bajt ze strumienia bajtowego) albo wartość -1 gdy czytanie sięga poza koniec pliku.
●
Możemy teraz użyć metody copy wobec dowolnych strumieni z odpowiednich konkretnych klas hierarchii klas strumieniowych, np.
By kopiowanie miało sens input musi być powiązane z konkretnym źródłem danych, a output – konkretnym odbiornikiem danych.
class Stream {
static void copy(InputStream in, OutputStream out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
}
static void copy(Reader in, Writer out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
} }
Stream.copy(input, output);
Strumień (w którymś momencie) musi być związany z
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Żródło/
odbiornik Strumienie znakowe Strumienie bajtowe
Wejście Wyjście Wejście Wyjście
Pamięć CharArrayWriter CharArrayWriter ByteArrayInputStream ByteArrayOutputStream
String StringReader StringWriter
Potok PipedReader PipedWriter PipedInputStream PipedOutputStream
Plik FileReader FileWriter FileInputStream FileOutputStream
Wymienione wyżej klasy pozwalają na powiązanie strumienia z konkretnym wejściem lub wyjściem.
Wyżej wymienione nie są jednak jedynymi, można tu wspomnieć np. o klasie GZIPInputStream który umożliwia obsługę strumieni spakowanych algorytmem gzip.
Wiązanie strumienia z danymi
źródła źródła
http://tutorials.jenkov.com/java-io/
pipes.html
Przykład
●
Chcielibyśmy wczytać informacje z jednego pliku tekstowego i zapisać do innego pliku
●
Potrzebujemy
–
Strumienia znakowego na wejściu wczytującego z pliku
–
Strumienia znakowego na wyjściu, zapisującego do pliku
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Przykład
●
Chcielibyśmy wczytać informacje z jednego pliku tekstowego i zapisać do innego pliku
●
Potrzebujemy
–
Strumienia znakowego na wejściu wczytującego z pliku FileReader
–
Strumienia znakowego na wyjściu, zapisującego do pliku
FileWriter
static public void main(String[] args) { try {
FileReader in1 = new FileReader("plik0.txt");
FileWriter out1 = new FileWriter("plik1.txt");
Stream.copy(in1, out1);
in1.close();
out1.close();
} catch(IOException exc) { exc.printStackTrace();
}
Przykład
●
Chcielibyśmy wczytać informacje z jednego pliku tekstowego i zapisać do innego pliku
●
Potrzebujemy
–
Strumienia znakowego na wejściu wczytującego z pliku FileReader
–
Strumienia znakowego na wyjściu, zapisującego do pliku FileWriter
Konstruktor przyjmuje np.
nazwę / ścieżkę do pliku
Po użyciu strumienie
zawsze zamkykamy!
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
static public void main(String[] args) { try {
FileReader in1 = new FileReader("plik0.txt");
FileWriter out1 = new FileWriter("plik1.txt");
Stream.copy(in1, out1);
in1.close();
out1.close();
} catch(IOException exc) { exc.printStackTrace();
}
Przykład
●
Chcielibyśmy wczytać informacje z jednego pliku tekstowego i zapisać do innego pliku
●
Potrzebujemy
–
Strumienia znakowego na wejściu wczytującego z pliku FileReader
–
Strumienia znakowego na wyjściu, zapisującego do pliku FileWriter
Możemy użyć kopiowania strumieni
zaprezentowanego wcześniej
Przypomnienie
●
Klasa która kopiuje strumień wejściowy do strumienia wyjściowego
– Uwaga: metoda read() zwraca liczbę całkowitą, reprezentującą kolejny znak ze
strumienia znakowego (lub bajt ze strumienia bajtowego) albo wartość -1 gdy czytanie sięga poza koniec pliku.
●
Możemy teraz użyć metody copy wobec dowolnych strumieni z odpowiednich konkretnych klas hierarchii klas strumieniowych, np.
By kopiowanie miało sens input musi być powiązane z konkretnym źródłem danych , a output – konkretnym odbiornikiem danych.
class Stream {
static void copy(InputStream in, OutputStream out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
}
static void copy(Reader in, Writer out) throws IOException { int c;
while ((c = in.read()) != -1) out.write(c);
} }
Stream.copy(input, output);
Strumień (w którymś momencie) musi być związany z
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Przykład II
●
Chcielibyśmy stworzyć strumień ze Stringa i zapisać do pliku
–
Strumienia znakowego na wejściu używającego zadeklarowanego Stringa (z pamięci)
–
Strumienia znakowego na wyjściu, zapisującego do pliku
Żródło/
odbiornik Strumienie znakowe Strumienie bajtowe
Wejście Wyjście Wejście Wyjście
Pamięć CharArrayWriter CharArrayWriter ByteArrayInputStream ByteArrayOutputStream
StringReader StringWriter
Potok PipedReader PipedWriter PipedInputStream PipedOutputStream
Plik FileReader FileWriter FileInputStream FileOutputStream
Wiązanie strumienia z danymi
– Strumienia znakowego na wejściu używającego
zadeklarowanego Stringa
Żródło/
odbiornik Strumienie znakowe Strumienie bajtowe
Wejście Wyjście Wejście Wyjście
Pamięć CharArrayWriter CharArrayWriter ByteArrayInputStream ByteArrayOutputStream
StringReader StringWriter
Potok PipedReader PipedWriter PipedInputStream PipedOutputStream
Plik FileReader FileWriter FileInputStream FileOutputStream
Wiązanie strumienia z danymi
– Strumienia znakowego na wejściu używającego zadeklarowanego Stringa
– Strumienia znakowego na wyjściu, zapisującego do pliku
static public void main(String[] args) { try {
String msg = "Ala ma kota";
StringReader in2 = new StringReader(msg);
FileWriter out2 = new FileWriter("plik2.txt");
Stream.copy(in2, out2);
in2.close();
out2.close();
} catch(IOException exc) { exc.printStackTrace();
}
Przykład II
StringReader w konstruktorze
przyjmuje String który ma być źródłem
●
Chcielibyśmy stworzyć strumień ze Stringa i zapisać do pliku
–
Strumienia znakowego na wejściu używającego zadeklarowanego Stringa
StringReader
–
Strumienia znakowego na wyjściu, zapisującego do pliku
FileWriter
static public void main(String[] args) { try {
String msg = "Ala ma kota";
StringReader in2 = new StringReader(msg);
FileWriter out2 = new FileWriter("plik2.txt");
Stream.copy(in2, out2);
in2.close();
out2.close();
} catch(IOException exc) { exc.printStackTrace();
}
Przykład II
●
Chcielibyśmy stworzyć strumień ze Stringa i zapisać do pliku
–
Strumienia znakowego na wejściu używającego zadeklarowanego Stringa
StringReader
–
Strumienia znakowego na wyjściu, zapisującego do pliku FileWriter
Przy używaniu strumieni ZAWSZE
łapiemy wyjątki IOException!
Uwagi
●
Komentarze:
– W podanym przykładzie używaliśmy jednej z wersji konstruktorów klas
strumieniowych związanych z plikami podaliśmy jako argument nazwę pliku → 4 klasy strumieni abstrakcyjnych
● można także utworzyć strumień plikowy podając jako argument konstruktora referenecję do obiektu klasy File (o tym zaraz)
– przy tworzeniu obiektów klas strumieniowych, związanych z plikami, odpowiednie pliki są otwierane;
● strumienie wejściowe są otwierane "tylko do odczytu",
● strumienie wyjściowe "tylko do zapisu".
● strumienie wyjściowe mogą być otwarte w trybie dopisywania (należy użyć konstruktora z drugim argumentem "append mode" = true); w takim przypadku dane będo dopisywane do końca strumienia,
– przy operacjach na strumieniach może powstać wyjątek klasy IOException
oznaczający błąd operacji (np. odczytu lub zapisu), a także wyjątki klas pochodnych FileNotFoundException (brak pliku) oraz EOFException (w trakcie operacji
czytania lub pozycjonowania osiągnięto koniec pliku),
●
Strumienie danych są wykorzystywane przez wiele programów nie tylko do odczytu plików, ale np. do przesyłania danych pomiędzy
poszczególnymi wątkami czy też do sieci.
Nie ma jedynej słusznej metody otwarcia pliku.
Istnieje wiele konstruktorów,
należy dobrać odpowiedni do danej sytuacji.
Uwagi
●
Komentarze:
– W podanym przykładzie używaliśmy jednej z wersji konstruktorów klas
strumieniowych związanych z plikami podaliśmy jako argument nazwę pliku → 4 klasy strumieni abstrakcyjnych
● można także utworzyć strumień plikowy podając jako argument konstruktora referenecję do obiektu klasy File (o tym zaraz)
– przy tworzeniu obiektów klas strumieniowych, związanych z plikami, odpowiednie pliki są otwierane;
● strumienie wejściowe są otwierane "tylko do odczytu",
● strumienie wyjściowe "tylko do zapisu".
● strumienie wyjściowe mogą być otwarte w trybie dopisywania (należy użyć konstruktora z drugim argumentem "append mode" = true); w takim przypadku dane będo dopisywane do końca strumienia,
– przy operacjach na strumieniach może powstać wyjątek klasy IOException
oznaczający błąd operacji (np. odczytu lub zapisu), a także wyjątki klas pochodnych FileNotFoundException (brak pliku) oraz EOFException (w trakcie operacji
czytania lub pozycjonowania osiągnięto koniec pliku),
●
Strumienie danych są wykorzystywane przez wiele programów nie tylko do odczytu plików, ale np. do przesyłania danych pomiędzy
poszczególnymi wątkami czy też do sieci.
FileWriter out = new FileWriter("plik.txt");
Plik domyślnie otworzy się “do zapisu”.
Nie ma metody “open”.
Uwagi
●
Komentarze:
– W podanym przykładzie używaliśmy jednej z wersji konstruktorów klas
strumieniowych związanych z plikami podaliśmy jako argument nazwę pliku → 4 klasy strumieni abstrakcyjnych
● można także utworzyć strumień plikowy podając jako argument konstruktora referenecję do obiektu klasy File (o tym zaraz)
– przy tworzeniu obiektów klas strumieniowych, związanych z plikami, odpowiednie pliki są otwierane;
● strumienie wejściowe są otwierane "tylko do odczytu",
● strumienie wyjściowe "tylko do zapisu".
● strumienie wyjściowe mogą być otwarte w trybie dopisywania (należy użyć konstruktora z drugim argumentem "append mode" = true); w takim przypadku dane będo dopisywane do końca strumienia,
– przy operacjach na strumieniach może powstać wyjątek klasy IOException
oznaczający błąd operacji (np. odczytu lub zapisu), a także wyjątki klas pochodnych FileNotFoundException (brak pliku) oraz EOFException (w trakcie operacji
czytania lub pozycjonowania osiągnięto koniec pliku),
●
Strumienie danych są wykorzystywane przez wiele programów nie tylko do odczytu plików, ale np. do przesyłania danych pomiędzy
poszczególnymi wątkami czy też do sieci.
Trzeba pamiętać o obsłudze wyjątków!
Należy chociaż wypisać printStackTrace()
który wypisuje w konsoli szczegóły problemu
Uwagi
●
Komentarze:
– W podanym przykładzie używaliśmy jednej z wersji konstruktorów klas
strumieniowych związanych z plikami podaliśmy jako argument nazwę pliku → 4 klasy strumieni abstrakcyjnych
● można także utworzyć strumień plikowy podając jako argument konstruktora referenecję do obiektu klasy File (o tym zaraz)
– przy tworzeniu obiektów klas strumieniowych, związanych z plikami, odpowiednie pliki są otwierane;
● strumienie wejściowe są otwierane "tylko do odczytu",
● strumienie wyjściowe "tylko do zapisu".
● strumienie wyjściowe mogą być otwarte w trybie dopisywania (należy użyć konstruktora z drugim argumentem "append mode" = true); w takim przypadku dane będo dopisywane do końca strumienia,
– przy operacjach na strumieniach może powstać wyjątek klasy IOException
oznaczający błąd operacji (np. odczytu lub zapisu), a także wyjątki klas pochodnych FileNotFoundException (brak pliku) oraz EOFException (w trakcie operacji
czytania lub pozycjonowania osiągnięto koniec pliku),
●
Strumienie danych są wykorzystywane przez wiele programów nie tylko do odczytu plików, ale np. do przesyłania danych pomiędzy
poszczególnymi wątkami czy też do sieci.
Strumienie często służą do obsługi plików,
ale nie tylko
Klasy strumieni
Szare elementy oznaczają związane z konkretnym źródłem/odbiornikiem dyskutowane przed chwilą, → 4 klasy strumieni abstrakcyjnych Białe - klasy przetwarzające (realizujące określone rodzaje przetwarzania) dyskutowane za chwilę.→ 4 klasy strumieni abstrakcyjnych
Klasy przetwarzające
●
Samo określenie strumienia często nie wystarcza.
●
Ciągnąc dalej analogię z hydrobudownictwem na tym etapie mamy już źródło
i rzekę. Teraz czas stawiać zapory i elektrownie.
Klasy przetwarzające
●
Samo określenie strumienia często nie wystarcza.
●
Ciągnąc dalej analogię z hydrobudownictwem na tym etapie mamy już źródło
i rzekę. Teraz czas stawiać zapory i elektrownie.
Klasy przetwarzające
●
Ciągnąc dalej analogię z hydrobudownictwem na tym
etapie mamy już źródło i rzekę. Teraz czas stawiać zapory.
●
Odpowiednikiem zapór są klasy przetwarzające
strumienie, służą one do tego aby nasze strumienie bajtów bądź znaków wykorzystać w użyteczny sposób.
●
Przykładem są klasy buforujące.
–
Dzięki temu program może działać szybciej, bo nie musi co
chwilę odwoływać się do danych (np. na dosyć powolnym dysku) a czyta je z bufora.
–
Życiowym przykładem takiego bufora jest lodówka, która
przechowuje (buforuje) nam kupione w sklepie produkty. Dzięki
niej nie musimy biegać co chwilę do sklepu.
Klasy przetwarzające
Rodzaj przetwarzania Strumienie znakowe Strumienie bajtowe Buforowanie BufferedReader,
BufferedWriter BufferedInputStream, BufferedOutputStream Filtrowanie FilterReader, FilterWriter FilterInputStream,
FilterOutputStream Konwersja: bajty-znaki InputStreamReader,
OutputStreamWriter
Serializacja obiektów ObjectInputStream,
ObjectOutputStream Czytanie typów prostych z
bajtów DataInputStream,
DataOutputStream
Zliczanie wierszy LineNumberReader LineNumberInputStream
Drukowanie PrintWriter PrintStream
Klasy przetwarzające
●
Jak użyć klasy przetwarzającej?
●
Konstruktory klas przetwarzających mają jako argument referencję do obiektów podstawowych klas abstrakcyjnych hierarchii dziedziczenia (InputSteram, OutputSteram, Reader, Writer).
●
Dlatego przetwarzanie (automatyczna transformacja) danych jest logicznie oderwana od fizycznego strumienia, stanowi swoistą na niego “nakładkę”.
●
Zatem zastosowanie klas przetwarzających wymaga:
–
stworzenia obiektu związanego z fizycznym źródłem/odbiornikiem,
–
stworzenie obiektu odpowiedniej klasy przetwarzającej, "nałożonego"
na fizyczny strumień.
Żródło: http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
Klasy przetwarzające
●
Jak użyć klasy przetwarzającej?
●
Zastosowanie klas przetwarzających wymaga:
–
stworzenia obiektu związanego z fizycznym źródłem/odbiornikiem
–
stworzenie obiektu odpowiedniej klasy przetwarzającej,
"nałożonego" na fizyczny strumień.
●
Przykład: najpierw trzeba stworzyć strumień wczytujący z pliku, a dopiero potem go zbuforować.
●
Taki "tasiemcowy" dostęp do zbuforowanych danych powoduje znaczne zwiększenie elastyczności kodu,
–
jeśli chce się np. tylko zmienić źródło strumienia wystarczy klasę FileInputStream zastąpić inną np. PipedInputStream. Reszty kodu zaś nie trzeba zmieniać..
BufferedInputStream bufferedInputStream
= new BufferedInputStream(new FileInputStream(from));
Do czego mogą służyć klasy przetwarzające?
●
Klasy buforujące
–
Zmniejszają liczbę fizycznych odwołań do urządzeń zewnętrznych. Przy czytaniu dużych plików tekstowych należy unikać bezpośredniego
czytania za pomocą klasy FileReader. To samo dotyczy zapisu.
●
Konwersja bajty-znaki
–
InputStreamReader czyta bajty ze strumienia definiowanego przez InputStream (strumień bajtowy) i zamienia je na znaki (16 bitowe), używając domyślnej lub podanej strony kodowej,
–
OutputStreamWriter wykonuje przy zapisie konwersję odwrotną.
●
Czytanie typów prostych z bajtów
–
DataInputStream i DataOutputStream są strumieniami bajtowymi, ale pozwalają czytać/pisać dane typów pierwotnych (np. short, char, int, float, double, boolean) ze/do strumieni bajtowych.
Żródło: http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
Do czego mogą służyć klasy przetwarzające?
●
Serializacja
–
służy do "utrwalania" obiektów po to, by odtworzyć je w innym kontekście (przy ponownym uruchomieniu programu lub w innym miejscu, np. programie działającym w innym miejscu sieci po
przekazaniu "utrwalonego" obiektu przez socket),
●
Klasy LineNumber...
–
zlicza wiersze strumienia przy czytaniu (i pozwala w każdym momencie uzyskać informację o numerze wiersza).
●
Klasy Print...
–
zawierają wygodne metody wyjścia (np. println). Niekoniecznie
oznacza to drukowanie fizyczne, często wykorzystywane jest w
powiązaniu z innymi strumieniami po to by łatwo wyprowadzać
informacje.
Przykład
●
Buforowanie wczytywanego pliku
– Czytanie linia po linii z pliku tekstowego
FileReader fr = new FileReader("plik.txt");
// tu powstaje związek z fizycznym źródłem
BufferedReader br = new BufferedReader(fr);
// tu dodajemy "opakowanie" umożliwiające buforowanie czytamy wiersz po wierszu
String line;
while ((line = br.readLine()) != null) {
// kolejny wiersz pliku: metoda readLine zwraca wiersz lub null jeśli koniec pliku
// ... tu coś robimy z odczytanym wierszem }
Przykład
●
Buforowanie wczytywanego pliku
– Czytanie linia po linii z pliku tekstowego
FileReader fr = new FileReader("plik.txt");
// tu powstaje związek z fizycznym źródłem
BufferedReader br = new BufferedReader(fr);
// tu dodajemy "opakowanie" umożliwiające buforowanie czytamy wiersz po wierszu
String line;
while ((line = br.readLine()) != null) {
// kolejny wiersz pliku: metoda readLine zwraca wiersz lub null jeśli koniec pliku
// ... tu coś robimy z odczytanym wierszem }
Przykład
●
Buforowanie wczytywanego pliku
– Czytanie linia po linii z pliku tekstowego
BufferedReader br = new BufferedReader(new FileReader("plik.txt"));
// tu powstaje związek z fizycznym źródłem oraz dodajemy "opakowanie"
umożliwiające buforowanie czytamy wiersz po wierszu String line;
while ((line = br.readLine()) != null) {
// kolejny wiersz pliku: metoda readLine zwraca wiersz lub null jeśli koniec pliku
// ... tu coś robimy z odczytanym wierszem }
Przykład II
●
Przykład buforowania: program, czytający plik tekstowy i zapisujący jego zawartość do innego pliku tekstowego wraz z numerami wierszy.
class Lines {
public static void main(String args[]) { try {
FileReader fr = new FileReader(args[0]);
LineNumberReader lr = new LineNumberReader(fr);
BufferedWriter bw = new BufferedWriter(
new FileWriter(args[1]));
String line;
while ((line = lr.readLine()) != null) {
bw.write( lr.getLineNumber() + " " + line);
bw.newLine();
}
lr.close();
bw.close();
} catch(IOException exc) {
System.out.println(exc.toString());
System.exit(1);
}
klasa LineNumberReader dziedziczy klasę BufferedReader,
dając możliwość uzyskania numeru wiersza
(metoda getLineNumber())
Przykład II
●
Przykład buforowania: program, czytający plik tekstowy i zapisujący jego zawartość do innego pliku tekstowego wraz z numerami wierszy.
class Lines {
public static void main(String args[]) { try {
FileReader fr = new FileReader(args[0]);
LineNumberReader lr = new LineNumberReader(fr);
BufferedWriter bw = new BufferedWriter(
new FileWriter(args[1]));
String line;
while ((line = lr.readLine()) != null) {
bw.write( lr.getLineNumber() + " " + line);
bw.newLine();
}
lr.close();
bw.close();
} catch(IOException exc) {
System.out.println(exc.toString());
System.exit(1);
} } }
klasa LineNumberReader dziedziczy klasę BufferedReader,
dając możliwość uzyskania numeru wiersza (metoda getLineNumber())
przy zamknięciu wyjściowego strumienia buforowanego zawartość bufora jest zapisywana
do strumienia; istnieje też metoda void flush( ), zapisujące dane które pozostały w buforze
a nie zostały jeszcze zapisane w miejscu przeznaczenia;
takie "ręczne" opróżnianie bufora jest czasem przydatne.
Przykład II
●
Przykład buforowania: program, czytający plik tekstowy i zapisujący jego zawartość do innego pliku tekstowego wraz z numerami wierszy.
class Lines {
public static void main(String args[]) { try {
FileReader fr = new FileReader(args[0]);
LineNumberReader lr = new LineNumberReader(fr);
BufferedWriter bw = new BufferedWriter(
new FileWriter(args[1]));
String line;
while ((line = lr.readLine()) != null) {
bw.write( lr.getLineNumber() + " " + line);
bw.newLine();
}
lr.close();
bw.close();
} catch(IOException exc) {
System.out.println(exc.toString());
System.exit(1);
}
Wyjątki:
łapiemy IOException
Przykład II
●
Przykład buforowania: program, czytający plik tekstowy i zapisujący jego zawartość do innego pliku tekstowego wraz z numerami wierszy.
class Lines {
public static void main(String args[]) { try {
FileReader fr = new FileReader(args[0]);
LineNumberReader lr = new LineNumberReader(fr);
BufferedWriter bw = new BufferedWriter(
new FileWriter(args[1]));
String line;
while ((line = lr.readLine()) != null) {
bw.write( lr.getLineNumber() + " " + line);
bw.newLine();
}
lr.close();
bw.close();
} catch(IOException exc) {
System.out.println(exc.toString());
System.exit(1);
} } }
zastosowanie metody newLine() z klasy BufferedWriter pozwala w niezależny od platformy systemowej
sposób zapisywać separatory wierszy
Klasy strumieni
Szare elementy oznaczają związane z konkretnym źródłem/odbiornikiem, Białe - klasy przetwarzające (realizujące określone rodzaje przetwarzania).
Inne ważne klasy IO/NIO File
Path
Przykłady
File
●
File, w przeciwieństwie do tego, co sugeruje nazwa, nie reprezentuje pliku
●
Reprezentuje nazwę (wraz ze ścieżką) danego pliku albo nazwę (wraz ze ścieżką) zbioru plików w katalogu
●
Konstruktory klasy file:
–
File(String pathname) – tworzy obiekt File na podstawie ścieżki podanej jako napis (to może być plik lub katalog)
–
File(File parent, String child) – tworzy obiekt File na podstawie innego obiektu File (zawierającego zbiór plików) i nazwy konkretnego pliku
–
File(String parent, String child) – tworzy obiekt File na podstawie ścieżki podanej jako napis (zawierającej zbiór plików) i nazwy konkretnego pliku
–
File(URI uri) – URI oznacza referencję Uniform Resource Identifier,
pozwala m.in linkować do źródeł zewnętrznych (np. z internetu).
File
●
Wybrane metody
–
public String getName() - zwraca nazwę pliku lub katalogu w postaci napisu
–
public String getPath() - zwraca ścieżkę w postaci napisu
–
public boolean isFile() - sprawdza, czy podany obiekt File jest zwykłym plikiem (a nie, np. katalogiem)
–
public String[] list() - żeby wyciągnąć nazwy pojedynczych plików ze zbioru używamy list() która zwraca tablicę
znaków
–
public boolean delete(): usuwa plik albo katalog na który wskazuje dany obiekt File
https://www.tutorialspoint.com/java/java_file_class.htm
File Przykład
import java.io.File;
public class FileDemo {
public static void main(String[] args) { File f = null;
String[] strs = { "test1.txt", "test2.txt" };
try {
// dla kazdego string w tablicy strs for (String s : strs) {
// stworz nowy obiekt File f = new File(s);
// true jesli wykonywalny
boolean bool = f.canExecute();
// znajdz sciezke absolutna
String a = f.getAbsolutePath();
// wypisz sciezke absolutna z informacja o wykonywalnosci System.out.print(a);
System.out.println(" is executable: " + bool);
}
} catch (Exception e) {
// jesli pojawi sie IO exception e.printStackTrace();
}
}
Wyjątki:
łapiemy IOException
Tworzymy nowy obiekt File
Wyciągamy dane o pliku
FileDemo.java
Path
●
Przed Javą SE 7 zawsze używano java.io.File
–
Ze względu na powszechność jej użycia, prawdopodobnie nigdy nie zostanie całkowicie wycofana / zastąpiona
●
Jednak wraz z Javą SE 7 powstała nowa klasa, Path, która robi to samo co File, tylko lepiej i więcej
–
Mamy dostęp do metadanych takich jak uprawnienia
(permissions) danego pliku, wsparcie dla linków symbolicznych, lepiej sobie radzi z bardzo dużymi katalogami, metoda
rename(..) działa tak samo na różnych platformach,
dokładniejsze informacje dotyczące sytuacji wyjątkowych
●
Ogólne zasady:
–
Dla nowych projektów lepiej używać Path
–
Na tą chwilę File nie można uznać za “przestarzałe”
Path
File Path
file = new File("path/to/file.txt") path = Paths.get("path/to/file.txt")
file = new File(parentFile, "file.txt") path = parentPath.resolve("file.txt")
file.getFileName() path.getFileName().toString()
file.delete() Files.delete(path)
// Microsoft Windows syntax
Path path = Paths.get("C:\\home\\joe\\foo");
// Linux syntax
Path path = Paths.get("/home/joe/foo");
path.toFile() file.toPath()
JFileChooser
JFileChooser chooser = new JFileChooser();
chooser.showDialog(null, "Wybierz");
chooser.getSelectedFile();
JFileChooser
●
Okienko pozwalające wybrać pik
public class JFileChooserExample {
public static void main(String[] args) { JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Wybierz plik");
//Otwarcie okienka; metoda blokuje się do czasu wybrania pliku lub zamknięcia okna
int result = chooser.showDialog(null, "Wybierz");
if (JFileChooser.APPROVE_OPTION == result){
System.out.println("Wybrano plik: " + chooser.getSelectedFile());
}else {
System.out.println("Nie wybrano pliku");
}}
Wyciągamy plik tylko jeśli użytkownik go wybrał
(a nie np. nacisnął X)
PlikiWyborFile.java
PlikiWyborPath.java
JFileChooser
●
Okienko pozwalające wybrać pik
public class JFileChooserExample {
public static void main(String[] args) { JFileChooser chooser = new JFileChooser();
chooser.setDialogTitle("Wybierz plik");
//Otwarcie okienka; metoda blokuje się do czasu wybrania pliku lub zamknięcia okna
int result = chooser.showDialog(null, "Wybierz");
if (JFileChooser.APPROVE_OPTION == result){
System.out.println("Wybrano plik: " +
chooser.getSelectedFile().toPath());
}else {
System.out.println("Nie wybrano pliku");
}}
}
PlikiWyborFile.java
PlikiWyborPath.java
Wczytywanie z pliku tekstowego
PlikiTekstoweOdczyt2.java
FileReader – łączymy strumień ze źródłem (plik.txt)
BufferedReader – buforujemy wczytywany plik
Wczytywanie linia po linii używając readLine
Zamknięcie strumienia
public class PlikiTekstoweOdczyt2 {
public static void main(String[] args) { FileReader fr = null;
String linia = "";
// OTWIERANIE PLIKU:
try {
fr = new FileReader("plik.txt");
BufferedReader bfr = new BufferedReader(fr);
// ODCZYT KOLEJNYCH LINII Z PLIKU:
while ((linia = bfr.readLine()) != null) { System.out.println(linia);
}
// ZAMYKANIE PLIKU fr.close();
} catch (Exception e) {
System.out.println("BLAD IO!");
System.exit(1);
Wczytywanie z pliku tekstowego
public class PlikiTekstoweOdczyt {
public static void main(String[] args) { FileReader fr = null;
String linia = "";
// OTWIERANIE PLIKU:
try {
fr = new FileReader("plik.txt");
} catch (FileNotFoundException e) {
System.out.println("BLAD PRZY OTWIERANIU PLIKU!");
System.exit(1);
}BufferedReader bfr = new BufferedReader(fr);
// ODCZYT KOLEJNYCH LINII Z PLIKU:
try {
while((linia = bfr.readLine()) != null){
System.out.println(linia);}
} catch (IOException e) {
System.out.println("BLAD ODCZYTU Z PLIKU!");
System.exit(2);
}
// ZAMYKANIE PLIKU
try {fr.close();} catch (IOException e) {
System.out.println("BLAD PRZY ZAMYKANIU PLIKU!");
System.exit(3);
}}
}
PlikiTekstoweOdczyt.java
Jeden wspólny blok try-catch można zastąpić kilkoma blokami szczegółowymi Otwarcie
Odczyt
Zamknięcie
public class PlikiTekstoweZapis {
public static void main(String[] args) {
String[] linie = { "Pierwsza linia tekstu do zapisania",
"druga linia - kilka liczb: (12), -23, 44.5, 2,5",
"trzecia linia " };
FileWriter fw = null;
try {
fw = new FileWriter("plik.txt");
BufferedWriter bw = new BufferedWriter(fw);
for (int i = 0; i < linie.length; i++) { bw.write(linie[i]);
bw.newLine();
}
bw.close();
} catch (IOException e) { e.printStackTrace();
} }
Zapisywanie do pliku tekstowego
PlikiTekstoweZapis.java
FileWriter – łączymy strumień z plikiem do zapisu (plik.txt)
BufferedReader – buforujemy zapisywany plik
Zapisujemy linia po linii używając write + newLine
Zamknięcie pliku
(zamykamy zewnętrzny strumień)
4 sposoby zapisu do pliku
●
FileWriter
– Podstawowa klasa do zapisu plików tekstowych; używaj jeśli liczba zapisów w programie jest niewielka
●
BufferedWriter
– Buforowanie umożliwia zmniejszenie ilości operacji IO; używaj jeśli spodziewasz się większej ilości zapisów do plików tekstowych
●
OutputStream
– Zapisuje dane w postaci bajtów a nie znaków; nie poradzi sobie z bardziej zaawansowanym znakami Unicode, ale można używać do zapisu zwykłego tekstu ASCII; używaj jeśli potrzebujesz zapisać dane (niekoniecznie tekst)
● BufferedOutputStream, jeśli mamy dużo zapisów bajtowych
●
Files.write
– Metoda dodana w Java SE 7, wewnętrznie wykorzystuje OutputStream
WriteToFile4Ways.java
Random Access Files
●
Jeśli potrzebujesz coś zapisać w konkretnym miejscu istniejącego pliku
–
a nie tworzyć nowy lub dopisywać na końcu
●
należy wtedy użyć RandomAccessFile
–
pozwala na zapisanie na konkretnej pozycji w danym pliku
●
Pozycja jest określana przez offset, przesunięcie, w stosunku do początku pliku.
●
Uwaga, wtedy istniejący tekst zostanie NADPISANY
private static void writeToFile(String filePath, String data, int position) throws IOException {
RandomAccessFile file = new RandomAccessFile(filePath, "rw");
file.seek(position);
file.write(data.getBytes());
file.close();
}
RandomAccessFileOdczyt.java
Odczyt zasobów zawartych w JAR
●
To się przyda na projektach
– jeśli mamy plik, który jest wewnątrz pliku JAR, możemy go otworzyć za pomocą wywołania:
– Przykład odczytu:
InputStream inputStream = OdczytPlikuZJAR.class
.getResourceAsStream("rekopis.txt");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = bufferedReader.readLine();
while (line != null) {
System.out.println(line);
line = bufferedReader.readLine();
}
getClass().getResourceAsStream("nazwa_pliku");
OdczytZPlikuJAR.java
Kodowanie
●
Czyli problemy z “krzaczkami”
Kodowanie
●
Z punktu widzenia informacji na dysku nie rozróżniamy plików
“znakowych” od “bajtowych”
– Dla obu informacja jest zapisana za pomocą bajtów
●
W przypadku plików tekstowych należy bajty przetworzyć na znaki.
Sposób w jaki bajty są zamieniane na znaki nazywany jest kodowaniem.
●
Popularne rodzaje kodowania:
– ASCII - pozwala zapisać znaki podstawowego alfabetu łacińskiego wykorzystując 1 bajt na zapis jednego znaku
– CP1250 - pozwala zapisać znaki podstawowego alfabetu łacińskiego oraz pewne znaki diakrytyczne (w tym polskie) wykorzysując 1 bajt na zapis jednego znaku
– UTF-8, UTF-16, UTF-32 - pozwala zapisać dowolne znaki, zużywając 1 (UTF-8), 2 (UTF-16) lub 4 (UTF-32) bajty na znak.
●
Najpopularniejsze jest UTF-8
●
Windows (języki środkowoeuropejskie) domyślnie używa CP-1250
●
Java używa kodowania UTF-16 jako wewnętrznej reprezentacji wszystkich
struktur, również string jest zbiorem znaków kodowanych w UTF-16.
Kodowanie
●
Najprostszą metodą na obsługę kodowania jest wczytanie
bajtów ze strumienia wejściowego i konwersja z odpowiednim kodowaniem przy użyciu konstruktora
–
new String(tablica_bajtów, "kodowanie").
●
By odczytać pliki tekstowe w jakimś kodowaniu należy uzyskać instancję klasy Charset.
–
Do uzyskania instancji klasy Charset służy metoda Charset.forName, przyjmująca nazwę danego kodowania:
–
Dodatkowo w Javie istnieje domyślne kodowanie możliwe do uzyskania za pomocą: Charset.defaultCharset().
–
Wczytanie pliku z wybranym kodowaniem:
InputStreamReader streamReader = new InputStreamReader(inputStream,
System.out.println("Kodowanie UTF-32: " + Charset.forName("UTF-32"));
System.out.println("Domyślne kodowanie w tym komputerze: " + Charset.defaultCharset());
Strumienie – przykładowe programy
●
Podstawy
●
BuforZnakowy.java – przykład użycia StringBuffer
●
Konsola.java – wczytanie i wypisanie tekstu w konsoli
●
Omawiane na wykładzie
●
FileDemo.java – używanie zmiennej File
●
PlikiTekstoweOdczyt(2).java - odczyt z plików tekstowych
●
PlikiTekstoweZapis.java – zapis do plików tekstowych
●
PlikiWyborFile.java, PlikiWyborPath.java – użycie JFileChooser
●
WriteToFile4Ways.java – cztery sposoby na zapisywanie do plików
●
RandomAccessFileOdczyt(Zapis).java – użycie RandomAccessFile
●
Inne
●
ListNotes.java – zapisywanie notatek do pliku tekstowego z konsoli
●
LoadObjects.java – zapisywanie obiektów klas (a nie tekstu / liczb)
●
SaveObjects.java – zapisywanie obiektów klas (a nie tekstu / liczb)
Więcej informacji
●
http://edu.pjwstk.edu.pl/wyklady/poj/scb/Strumienie/Strumienie.html
●
http://www.samouczekprogramisty.pl/strumienie-w-jezyku-java/
●
http://pojava.fizyka.pw.edu.pl/index.php/laboratoria/laboratorium-4
●
https://docs.oracle.com/javase/tutorial/essential/io/pathOps.html
Quiz time
Pytanie 1
●
Regularnie chcielibyśmy zapisywać do pliku wyniki symulacji. Plik ma format tekstowy. Którego strumienia
powinniśmy użyć do obsługi zapisu?
(a) InputStream (b) OutputStream (c) FileWriter
(d) BufferedWriter
Pytanie 1
●
Regularnie chcielibyśmy zapisywać do pliku wyniki symulacji. Plik ma format tekstowy. Którego strumienia
powinniśmy użyć do obsługi zapisu?
(a) InputStream (b) OutputStream (c) FileWriter
(d) BufferedWriter
Pytanie 2
●
Ile strumieni wyjściowych możemy mieć otwartych na raz?
(a) Zawsze tylko jeden na raz
(b) Jeden danego typu (1 wejściowy i 1 wyjściowy) (c) Wiele
(tyle, na ile pozwolą nam zasoby systemu)
Pytanie 2
●
Ile strumieni wyjściowych możemy mieć otwartych na raz?
(a) Zawsze tylko jeden na raz
(b) Jeden danego typu (1 wejściowy i 1 wyjściowy) (c) Wiele
(tyle, na ile pozwolą nam zasoby systemu)
Pytanie 3
●
Połącz domyślne kodowania do środowiska
(a) CP1250 (b) UTF-8 (c) UTF-16
(a) Linux (b) Java
(c) Windows
Pytanie 3
●
Połącz domyślne kodowania do środowiska
(a) CP1250 (b) UTF-8 (c) UTF-16
(a) Linux (b) Java
(c) Windows
Pytanie 4
●
Jeśli napisy w programie mi się brzydko krzaczą
– “panieĹ„skim rumieĹ„cem dziÄ™cielina”
jak najlepiej mogę zaradzić problemowi?
(a) Skasować wszystkie polskie znaki
(b) Sprawdzić, w jakim kodowaniu został zapisany problematyczny tekst i odpowiednio go
wczytywać
(c) Zmienić ustawienia w Javie by automatycznie
zawsze dobrze wczytywała wszystkie teksty
Pytanie 4
●
Jeśli napisy w programie mi się brzydko krzaczą
– “panieĹ„skim rumieĹ„cem dziÄ™cielina”
jak najlepiej mogę zaradzić problemowi?
(a) Skasować wszystkie polskie znaki
(b) Sprawdzić, w jakim kodowaniu został zapisany problematyczny tekst i odpowiednio go
wczytywać
(c) Zmienić ustawienia w Javie by automatycznie zawsze dobrze wczytywała wszystkie teksty
Cudów ni ma.
Prosta grafika w Javie
Dodawanie obrazów do projektu
Dodajemy obrazek do konkretnego pakietu
PPM na nazwie pakietu → 4 klasy strumieni abstrakcyjnych Import… File System → 4 klasy strumieni abstrakcyjnych → 4 klasy strumieni abstrakcyjnych
Browse.. Wybrać katalog → 4 klasy strumieni abstrakcyjnych → 4 klasy strumieni abstrakcyjnych Wybrać plik z listy Finish → 4 klasy strumieni abstrakcyjnych
Import…
1
2
3
4
5 – wybór z listy
6
Dodawanie obrazów do projektu
Dodajemy obrazek do konkretnego pakietu
PPM na nazwie pakietu → 4 klasy strumieni abstrakcyjnych Import… File System → 4 klasy strumieni abstrakcyjnych → 4 klasy strumieni abstrakcyjnych
Browse.. Wybrać katalog → 4 klasy strumieni abstrakcyjnych → 4 klasy strumieni abstrakcyjnych Wybrać plik z listy Finish → 4 klasy strumieni abstrakcyjnych
Import…
1
2
3
5 – wybór z 4 listy
nazwa_pakietu/nazwa_obrazka.JPG
Rysowanie obrazka na panelu
public class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel() { super();
// Plik umieszczony w podpakiecie "obrazki"
URL resource = getClass().getResource("obrazki/zdjecie.JPG");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
Dimension dimension =
new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension);
}
public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
} }
ImagePanel.java
Rysowanie obrazka na panelu
public class ImagePanel extends JPanel {
private BufferedImage image;
public ImagePanel() { super();
// Plik umieszczony w podpakiecie "obrazki"
URL resource = getClass().getResource("obrazki/zdjecie.JPG");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
System.err.println("Blad odczytu obrazka");
e.printStackTrace();
}
Dimension dimension =
new Dimension(image.getWidth(), image.getHeight());
setPreferredSize(dimension);
}
public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, 0, 0, this);
}
ImagePanel.java
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Grafika
Grafika (Java2D)
Klasa Graphics2D – dużo większe możliwości tworzenia grafiki (m.in. łatwa obsługa przezroczystości, wypełnienia gradientowe, transformacje geometryczne, …)
• SimpleGraphics.java
– przykład wykorzystania klasy Graphics2d
• Gradient.java
– przykład wypełniania gradientowego
• TextureGraphics.java
– przykład wykorzystania tekstur
• SaveImage.java
– przykład tworzenia buforowanego obrazka i zapisu do
pliku graficznego.
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Przykład rysowania przy użyciu Graphics 2d
// Tworzenie ksztaltu i rysowanie wypelnienienia - fill Ellipse2D e=new Ellipse2D.Double(80,80,180,80);
g2.setPaint(Color.cyan);
g2.fill(e);
// Kontruktor Color() z czterema argumentami float // czwarty odpowiada za "przezroczystosc":
g2.setColor(new Color(1.0f, 1.0f, 0.0f, 0.6f));
g2.fill(star);
g2.setColor(new Color (0.2f, 0.2f, 0.2f, 0.5f));
g2.draw(star);
// Tworznie ksztaltu i rysownanie konturu - draw // set Stroke ustawia wlasciwosci linii
Rectangle2D r=new Rectangle2D.Double(50,50,100,200);
g2.setPaint(c0);
g2.setStroke(new BasicStroke(10));
g2.draw(r);
SimpleGraphics.java
Przykład wykorzystania tekstur przy użyciu Graphics 2d
// wykorzystanie tekstury do rysowania, tekstu itp. - setPaint()
TexturePaint tp = new TexturePaint(im, new Rectangle(imW,imH));
g2.setPaint(tp);
g2.fill(new RoundRectangle2D.Float(75,20,150,200,30,30));
g2.setFont(new Font("Verdana",Font.BOLD,24));
g2.drawString("Here's the text",10,260);
BufferedImage im =
new BufferedImage(imW,imH,
BufferedImage.TYPE_INT_RGB);
// nalezy wypełnić odpowiednim wzorem BufferedImage im, np.
Graphics2D g2im = im.createGraphics();
g2im.setColor(new Color(192,192,192));
g2im.fillRect(0,0,imW,imH);
//albo wczytać obrazek
TextureGraphics.java
Programowanie Obiektowe (Wykład) Małgorzata Janik (WF PW)
Przykład wykorzystania tekstur przy użyciu Graphics 2d
// wykorzystanie tekstury do rysowania, tekstu itp. - setPaint()
TexturePaint tp = new TexturePaint(im, new Rectangle(imW,imH));
g2.setPaint(tp);
g2.fill(new RoundRectangle2D.Float(75,20,150,200,30,30));
g2.setFont(new Font("Verdana",Font.BOLD,24));
g2.drawString("Here's the text",10,260);
BufferedImage im =
new BufferedImage(imW,imH,
BufferedImage.TYPE_INT_RGB);
// nalezy wypełnić odpowiednim wzorem BufferedImage im, np.
Graphics2D g2im = im.createGraphics();
g2im.setColor(new Color(192,192,192));
g2im.fillRect(0,0,imW,imH);
//albo wczytać obrazek
TextureGraphics.java
try {
ImageIO.write( im, "png" /* "png" "jpeg" ... format desired */, new File ( "gwiazda.png" ) /* target */ );
} catch (IOException e1) { e1.printStackTrace();
System.out.println("Blad przy zapisywaniu obrazku do pliku");
System.exit(1);
}
Zapisywanie obrazka do pliku
BufferedImage im;
// nalezy zadeklarować odpowiednio obrazek
SaveImage.java
Tworzenie i korzystanie z plików JAR
Biblioteka JFreeChart
Czym są pliki JAR?
●
JAR (ang. Java ARchive)
– archiwum ZIP używane do strukturalizacji i kompresji plików klas języka Java oraz
powiązanych z nimi zasobów i metadanych.
●
Archiwum JAR, o ile posiada
wyszczególnioną klasę główną, może
stanowić osobną aplikację
http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
●
Archiwum JAR powinno zawierać plik manifestu umieszczony w ścieżce
– META-INF/MANIFEST.MF,
który informuje o sposobie użycia, przeznaczeniu archiwum, wskazuje klasę główną jeśli archiwum jest wykonywalne itp.
●
Większość współczesnych IDE dla Javy pozwala na szybkie tworzenie plików JAR i generowanie plików manifestu
Plik manifestu
Tworzenie pliku JAR w Eclipse – poprzez eksport projektu/projektów
Można tworzyć „zwykłe”
archiwum JAR, lub uruchamialne archiwum ze
wskazaniem klasy głównej