Strumienie w języku Java Bartosz Walter InMoST Wielkopolska sieć współpracy w zakresie innowacyjnych metod wytwarzania oprogramowania Termin realizacji: – Szkolenie finansowane ze środków Europejskiego Funduszu Społecznego (75%) i budżetu państwa (25%) w ramach Zintegrowanego Programu Operacyjnego Rozwoju Regionalnego
Wprowadzenie Podstawowy mechanizm wejścia-wyjścia znajduje się w Javie w pakiecie java.io.* Obejmuje następujące obszary funkcjonalne reprezentacja plików i katalogów klasy odczytujące i zapisujące dane do plików obsługa wyjątków związanych z wejściem-wyjściem
Klasa java.io.File Obiekty klasy java.io.File reprezentują ścieżkę do pliku albo katalogu (niezależnie od tego, czy one istnieją) Stanowią one punkt wejścia dla wszystkich operacji zapisu i odczytu danych, ale za ich pomocą nie można bezpośrednio dokonywać tych czynności File plik = new File("c:/dane.txt"); File katalog = new File("c:/moje dokumenty"); File plik2 = new File(katalog, "nowy plik.txt")
Wybrane metody klasy java.io.File String getName() – zwraca nazwę pliku String getAbsolutePath() – zwraca pełną ścieżkę pliku boolean exists() – czy plik istnieje? boolean canWrite() – możliwość zapisu boolean canRead() – możliwość czytania boolean isFile() – czy jest plikiem? boolean isDirectory() – czy jest katalogiem int length() – rozmiar pliku File plik = new File("c:/moje dokumenty/plik.txt");
Wybrane metody klasy java.io.File String[] list() – zwraca tablicę z nazwami plików znajdujących się w katalogu boolean renameTo(File nowy) – zmiana nazwy boolean mkdirs() – utworzenie hierarchii katalogów opisanych w konstruktorze boolean delete() – kasowanie pliku boolean createNewFile() – utworzenie nowego pliku File plik = new File("c:/moje dokumenty/plik.txt");
Klasa java.io.File - przykład File katalog1 = new File("c:/katalog/katalog1"); File katalog2 = new File("c:/katalog/katalog2"); // tworzymy katalog katalog1.mkdirs(); // zmieniamy jego nazwę katalog1.renameTo(katalog2);
Czym są strumienie? Alamakota... strumień danych W Javie mechanizm wejścia-wyjścia opiera się na pojęciu strumienia (ang. stream ) Strumień to tor komunikacyjny pomiędzy dowolnym źródłem i przeznaczeniem danych. Zasadniczo strumienie są jednokierunkowe, tzn. z jednej strony przyjmują dane (można do nich zapisać), a z drugiej wysyłają (można z nich odczytać)
Strumień wejściowy źródło Alamakota... program strumień danych odczyt zapis Czytaj.java
Strumień wyjściowy program Alamakota... przeznaczenie strumień danych zapis odczyt Pisz.java
Strumienie w Javie Ze względu na rodzaj przetwarzanych danych strumienie w Javie dzielą się na strumienie znakowe, służące do przesyłania znaków Unicode strumienie binarne, służące do przesyłania dowolnych bajtów Cykl życia strumienia składa się z trzech faz: utworzenia, odczytu/zapisu, zamknięcia strumieńznakowybinarny wejściowy java.io.Readerjava.io.InputStream wyjściowy java.io.Writerjava.io.OutputStream
Znakowe strumienie plikowe Służą do przesyłania znaków w standardzie Unicode o 16-bitowych kodach Mogą odczytywać (klasa FileReader ) lub zapisywać (klasa FileWriter ) pojedyncze znaki Często wewnętrznie obsługują przekodowanie znaków związane z niestandardowymi alfabetami prosty strumień plik na dysku odczyt/zapis danych na dysku odczyt/zapis pojedynczych znaków
Odczyt z pliku tekstowego Strumień FileReader odczytuje ze strumienia znakowego otwartego w pliku pojedyncze znaki Wybrane metody: int read() – odczyt jednego znaku (liczby int ) int read(char[] blok) – odczyt tablicy znaków void close() – zamknięcie strumienia FileReader plik = new FileReader("plikwe.txt"); char znak; do { znak = (char) plik.read(); } while (znak != -1); plik.close();
Zapis do pliku tekstowego Strumień FileWriter zapisuje do strumienia znakowego otwartego w pliku pojedyncze znaki Wybrane metody void write(int znak) – zapis jednego znaku void write(char[] blok) – zapis tablicy znaków void write(String napis) – zapis napisu void append(char znak) – dołączenie znaku na końcu pliku void flush() – opróżnienie strumienia void close() – zamknięcie strumienia FileWriter plik = new FileWriter ("plik.wy"); //utworz. plik.write('A'); // zapis do strumienia plik.close(); // zamknięcie strumienia
Buforowanie Bezpośredni odczyt i zapis pojedynczych znaków jest nieefektywny (przykład: odczytaj znaków w pętli) Z pomocą przychodzą strumienie buforujące, które operują na innych, prostszych strumieniach i posiadają możliwość buforowania danych, aby można było przetwarzać większe ich porcje prosty strumień plik na dysku strumień buforujący odczyt/zapis danych na dysku odczyt/zapis pojedynczych znaków odczyt/zapis bloków danych
Buforowanie - przykład public class Kopiowanie { public static void main(String[] args) { try { FileReader we = new FileReader("C:/plik1.txt"); BufferedReader buforWe = new BufferedReader(we); FileWriter wy = new FileWriter("C:/plik2.txt"); BufferedWriter buforWy = new BufferedWriter(wy); String linia; while ((linia = buforWe.readLine()) != null) { buforWy.write(linia); } buforWe.close(); buforWy.close(); } catch (IOException ex) { System.err.println("Błąd: " + e); } }
Binarne strumienie plikowe Binarne strumienie służą do odczytu (klasa FileInputStream) i zapisu (klasa FileOutputStream) danych binarnych. Podstawową jednostką zapisu jest bajt (8 bitów). W strumieniach binarnych, inaczej niż w tekstowych, nigdy nie dochodzi do przekodowania danych. Są one zapisywane dokładnie w takiej postaci, w jakiej je przekazano. FileInputStream in = new FileInputStream("plik.we"); FileOutputStream out = new FileOutputStream("plik.wy");
Odczyt z pliku binarnego Strumień FileInputStream odczytuje ze strumienia binarnego otwartego w pliku pojedyncze bajty Wybrane metody: int read() – odczyt jednego znaku (liczby int ) int read(byte[] blok) – odczyt tablicy bajtów void close() – zamknięcie strumienia FileInputStream plik = new FileInputStream("plikwe.dat"); int bajt; do { bajt = plik.read(); } while (bajt != -1); // odczyt dopóki nie wystąpi koniec pliku plik.close(); // zamknięcie strumienia
Odczyt z pliku binarnego public class OdczytBinarny { public static void main(String[] args) { try { FileInputStream we = new FileInputStream("x"); byte bajt; while ((bajt = we.read()) != -1 { //... } strumienWe.close(); } catch (IOException ex) { System.err.println("Błąd: " + e); }
Zapis do pliku binarnego Strumień FileOutputStream zapisuje do strumienia binarnego otwartego w pliku pojedyncze bajty Wybrane metody void write(int znak) – zapis jednego bajtu void write(byte[] blok) – zapis tablicy bajtów void flush() – opróżnienie strumienia void close() – zamknięcie strumienia FileWriter plik = new FileWriter ("plikwy.dat"); plik.write('A'); // zapisany zostaje kod znaku 'A' plik.close();
Zapis do pliku binarnego public class ZapisBinarny { public static void main(String[] args) { try { FileOuputStream wy = new FileOutputStream("plik.wy"); for (int i = 0; i < 255; i++) { strumienWy.write(i); } strumienWy.close(); } catch (IOException ex) { System.err.println("Błąd: " + e); }
Buforowanie dostępu do pliku binarnego Podobnie jak w przypadku strumieni znakowych, strumienie binarne też mogą być buforowane Odpowiadają za to klasy BufferedInputStream i BufferedOutputStream Zapis buforowany ( BufferedOutputStream ) int write(byte[] bufor, int poczatek, int długosc) Odczyt buforowany ( BufferedInputStream ) int read(byte[] bufor, int poczatek, int długosc) while ((int liczba = strumien.read(bufor, 0, bufor.length) ) != -1) liczba faktycznie odczytanych bajtów bufor, jego początek i długość -1 oznacza koniec pliku
Buforowany odczyt - przykład public class BuforOdczytBinarny { public static void main(String[] args) { try { FileInputStream we = new FileOutputStream("pl.wy"); BufferedInputStream buforWe = new BufferedInputStream (we); char[] bufor = new char[1024]; while ((int liczba = buforWe.read(bufor, 0, bufor.length)) != -1) { // tu można coś zrobić z zawartością bufora } buforWe.close(); } catch (IOException ex) { System.err.println("Błąd: " + e); }
Standardowe wejście-wyjście Pojęcie "standardowe wejście-wyjście" odnosi się do koncepcji wywodzących się z Unixa Każdy program może wczytywać dane wejściowe ze standardowego wejścia oraz zapisywać dane wyjściowe na standardowe wyjście i standardowe wyjście błędów Strumienie System.in, System.out,System.err są obiektami i można z nich korzystać tak jak ze strumieni reprezentujących pliki. BufferedReader reader = new BufferedReader( new InputStreamReader(System.in));
Wyjątek IOException Niemal wszystkie operacje wejścia-wyjścia zgłaszają wyjątek IOException, dlatego wykonanie większości z nich wymaga objęcia w klauzulę try...catch