Przygotował: Jacek Sroka 1 Programowanie obiektowe Wykład 8 Strumienie
Przygotował: Jacek Sroka 2 Przypomnienie Reagowanie na sytuacje wyjątkowe Wyjątki nadzorowane i nienadzorowane Obsługa wyjątku try catch finally Rozwijanie stosu Składowe wyjątku Wsparcie ze strony kompilatora Zwalnianie zasobów Wyjątki a tworzenie i inicjalizacja Wyjątki a rozszerzanie Dobre praktyki
Przygotował: Jacek Sroka 3 Przykład wejścia w Javie import java.io.filereader; import java.io.ioexception; public class ZnakPoZnaku { public static void main(string[] args) throws IOException { // wersja dla Linuxa FileReader rd = new FileReader("/tmp/io_test.txt"); // wersja dla Windows // FileReader rd = new FileReader("c:\\io_test.txt"); try { int i; // Reader.read() zwraca wartość z przedziału 0 to 65535, // jeżeli odczyt się powiódł lub -1 jak nie while ((i = rd.read())!= -1) System.out.print((char) i); finally { rd.close();
Przygotował: Jacek Sroka 4 System wejścia/wyjścia Czemu to musi być rozległe Dane mogą pochodzić z różnych mediów: konsola, pliki, połączenia sieciowe, Różne sposoby obsługi: sekwencyjnie, ze swobodnym dostępem, buforowanie, znakowo/binarnie, znak po znaku/linia po linii,... Czasami konieczne dodatkowe przetwarzanie: liczenie sumy kontrolnej, kompresja, szyfrowanie, Wzorzec Dekorator Przykład: okienko z suwakiem Strumienie (ang. stream) InputStream, OutputStream, Reader, Writer Znakowe od Javy 1.1 Znakowe nie zastępują binarnych Łatwa konwersja z binarnych na znakowe (przydatna np. przy kompresji)
Przygotował: Jacek Sroka 5 Przykład konwersji import java.io.*; public class KonwersjaStrumieni { public static void main(string[] args) throws IOException { String napis = "Test strumieni.\nąćęłńóśźż\n"; ByteArrayOutputStream os = new ByteArrayOutputStream(); // OutputStream jest przekrztałcany na Writer Writer wr = new OutputStreamWriter(os); wr.write(napis); wr.close(); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); // InputStream jest przekształcany na Reader Reader rd = new InputStreamReader(is); int i; while ((i = rd.read())!= -1) System.out.print((char) i); rd.close();
Przygotował: Jacek Sroka 6 Strumienie Standardowe strumienie są dla: plików, tablic bajtów/znaków, obiektów String, łączach (ang. pipe) Wiele innych obiektów pozwala otrzymać strumień: Socket, URL File{Input,OutputStream i File{Reader,Writer pozwalają odczytywać i zapisywać pliki dyskowe Nazwa pliku lub obiekt File jako parametr konstruktora Dla obiektów wyjściowych drugi parametr wskazuje czy dopisywać na końcu ByteArray{Input,OutputStream i CharArray{Reader,Writer bufor w pamięci oparty na tablicy odpowiednio bajtów lub znaków Dla ob. wejściowego przekazujemy tablicę Dla ob. wyjściowego początkowy rozmiar bufora
Przygotował: Jacek Sroka 7 Strumienie StringBufferInputStream (nie ma odpowiednika do zapisu i jest deprecated) String{Reader,Writer bufor w pamięci oparty na napisie String (implementacja posługuje się obiektem StringBuffer) Dla ob. wejściowego przekazujemy napis Dla ob. wyjściowego początkowy rozmiar bufora Piped{Input,OutputStream i Piped{Reader,Writer łącze do komunikacji między procesami Najpierw tworzymy obiekt jedne rodzaju (konstr. bezparametrowy) Potem przekazujemy konstruktorowi obiektu drugiego rodzaju Strumienie zostają połączone łączem
Przygotował: Jacek Sroka 8 Podstawowe operacje na danych read() następny bajt/znak lub -1 jak koniec strumienia read(byte[]) lub read(char[]) odczytuje dane do tablicy, zwraca liczbę odczytanych porcji (chyba że już koniec wtedy -1), blokuje się dopóki nie napotka końca read(byte[], int, int) lub read(char[], int, int) analogicznie wypełnia podtablicę write(byte) lub write(char) zapisuje jedną porcję danych Analogiczne wersje dla tablic i tablic z przedziałami Wersja znakowa może zapisywać napisy i ich wycinki Strumienie trzeba zamykać close()
Przygotował: Jacek Sroka 9 Kodowanie znaków W Javie znaki są wewnętrznie kodowane w Unicode 16bit Użycie bezparametrowych konstruktorów {Input,OutputStreamWriter skutkuje konwersją do dla domyślnego kodowania danej platformy oba konstruktory są przeciążone i można jawnie wskazać kodowanie Również File{Reader,Writer stosują domyślne kodowanie to tylko opakowanie na {Input,OutputStreamWriter
Przygotował: Jacek Sroka 10 Konkatenacja strumieni import java.io.*; public class KonkatenacjaStrumieni { public static void main(string[] args) throws IOException { String danedlabufora1 = "Dane dla bufora 1.\nąćęłńóśźż\n"; String danedlabufora2 = "Dane dla bufora 2.\nąćęłńóśźż\n"; // getbytes() zwraca tablicę bajtów repr. kolejne znaki napisu // w domyślnym dla danej platformy kodowaniu znaków // (są też wersje przeciążone) ByteArrayInputStream is1 = new ByteArrayInputStream(daneDlaBufora1.getBytes()); ByteArrayInputStream is2 = new ByteArrayInputStream(daneDlaBufora2.getBytes()); // jest też konstruktor przyjmujący Enumeration<? extends InputStream> SequenceInputStream seq = new SequenceInputStream(is1, is2); Reader rd = new InputStreamReader(seq); int i; while ((i = rd.read())!= -1) System.out.print((char) i);
Przygotował: Jacek Sroka 11 Wzorzec Dekorator
Przygotował: Jacek Sroka 12 Przykłady Dekoratorów Buffered{Input,OutpuStream i Buffered{Reader,Writer Dodaje buforowanie (istotne dla efektywności) Do natychmiastowego opróżnienia bufora służy flush() Zazwyczaj bufor jest opróżniany również przy close() PrintStream i PrintWriter Dodatkowe metody wypisujące dane w sposób czytelny dla człowieka w dwóch wersjach print() i println() Dla wygody klasy posiadają dodatkowe konstruktory, które zwalniają z konieczności otwierania samemu strumienia do pisania na pliku i dekorowania go buforowaniem Zalecana jest PrintWriter, gdyż zapisuje końce linii w sposób przyjęty na danej platformie Uwaga: metody nie przepuszczają IOException, trzeba używać metody checkerror() PushBackInputStream i PushBackReader Dodają metodę unread() pozwalającą odesłać z powrotem ostatnio odczytane dane Odesłane dane są zapamiętywane w buforze. Kolejne odczyty najpierw pobierają dane z bufora, a dopiero jak jest pusty ze strumienia Przydaje się podczas budowy kompilatora.
Przygotował: Jacek Sroka 13 Przykłady Dekoratorów c.d. LineNumberInputStream i LineNumberReader Dodają metodę getlinenumber(), która zwraca liczbę odczytanych do tej pory linii LineNumberInputStream jest oznaczona jako deprecated Data{Input,OutputStream (brak odpowiedników znakowych) Dodają nowe metod do przesyłania przez strumień wartości typów podstawowych oraz napisów w sposób niezależny od platformy Object{Input,OutputStream (brak odpowiedników znakowych) Dodają nowe metody pozwalające przesyłać przez strumień obiekty implementujące interfejs java.io.serializable
Przygotował: Jacek Sroka 14 Przykłady Dekoratorów c.d. Checked{Input,OutputStream (brak odpowiednika znakowego) Wylicza sumę kontrolną dla danych przesyłanych przez strumień Należą do pakietu java.util.zip GZIP{Input,OutputStream (brak odpowiedników znakowych) Dane przesyłane przez strumień są kompresowane przy pomocy prostego algorytmu GZIP. Należą do pakietu java.util.zip Zip{Input,OutputStream (brak odpowiedników znakowych) Dane przesyłane przez strumień są kompresowane przy pomocy algorytmu Zip Należą do pakietu java.util.zip Cipher{Input,OutputStream (brak odpowiedników znakowych) Dane przesyłane przez strumień są szyfrowane lub deszyfrowane przy pomocy obiektu Cipher Należą do pakietu java.crypto
Przygotował: Jacek Sroka 15 Filmik
Przygotował: Jacek Sroka 16 Standardowe we/wy Standardowe wejście System.in InputStream BufferedReader stin = new BufferedReader(new InputStreamReader(System.in)); Scanner in = new Scanner(System.in); Standardowe wyjście System.out PrintStream Standardowe wyjście błędu System.oerr PrintStream Programy można łączyć w potoki Przekierowanie setout(printstream), setin(inputstream) i seterr(printstream)
Przygotował: Jacek Sroka 17 Przykład kompresja public class KompresjaGZIP { public static void main(string[] args) throws IOException { String nazwapliku = "/tmp/io_test.gzip"; BufferedOutputStream os = new BufferedOutputStream( new GZIPOutputStream( new FileOutputStream(nazwaPliku))); PrintWriter pw = new PrintWriter( new OutputStreamWriter(os)); pw.write("kompresja w Javie jest prosta"); pw.close(); // dekompresja BufferedInputStream is = new BufferedInputStream( new GZIPInputStream( new FileInputStream(nazwaPliku))); BufferedReader br = new BufferedReader( new InputStreamReader(is)); String s; while ( (s = br.readline())!= null ) System.out.println(s); br.close();
Przygotował: Jacek Sroka 18 Przykład kompresja ZIP public class KompresjaZip { public static void main(string[] args) throws IOException { String nazwapliku = "/tmp/io_test.zip"; int x; ZipOutputStream zos = new ZipOutputStream(...); for (int i = 1; i < args.length; i++) { System.out.println("Zapisywanie " + args[i]); BufferedInputStream in = new BufferedInputStream(new FileInputStream(args[0]+args[i])); zos.putnextentry(new ZipEntry(args[i])); while ( (x = in.read())!= -1 ) zos.write(x); in.close(); zos.close(); ZipInputStream zis = new ZipInputStream(...); ZipEntry ze; while ( (ze = zis.getnextentry())!= null ) { System.out.println(); System.out.println("Odczytywanie: " + ze); while ( (x = zis.read())!= -1 ) System.out.write(x); System.out.flush(); zis.close(); //np. java KompresjaZip /home/mójużytkownik/ a.txt b.txt podkat\c.txt podkat\d.txt
Przygotował: Jacek Sroka 19 NIO New I/O = Non-blocking I/O = NIO