• Nie Znaleziono Wyników

• Strumień ukrywa szczegóły związane z rzeczywistymi operacjami wykonywanymi na danych w urządzeniach we/wy.

N/A
N/A
Protected

Academic year: 2021

Share "• Strumień ukrywa szczegóły związane z rzeczywistymi operacjami wykonywanymi na danych w urządzeniach we/wy. "

Copied!
10
0
0

Pełen tekst

(1)

Biblioteki wejścia/wyjścia

Strumienie we/wy (I/O)

Pojęcie strumienia

• Strumień reprezentuje źródło lub odbiorcę danych (obiekt zdolny odbierać lub

produkować dane).

• Strumień ukrywa szczegóły związane z rzeczywistymi operacjami wykonywanymi na danych w urządzeniach we/wy.

• Hierarchię klas biblioteki we/wy moŜna podzielić ze względu na kierunek

przepływu danych (wejście i wyjście) oraz na elementarne jednostki danych

Strumienie:

• bajtowe

• InputStream

• OutputStream

• znakowe

• Reader

• Writer

Strumienie bajtów stosuje się do danych binarnych (obraz, dźwięk), strumienie znakowe do sformatowanych danych liczbowych i oczywiście tekstu. Preferować znakowe (Unicode, efektywniejsze)

Unicode (UCS)

• Reprezentacja 2-bajtowa

• MoŜliwość prezentacji, wymiany i

przetwarzania tekstów w róŜnych językach

• Około 50 000 znaków

• www.unicode.org

• 127 pierwszych znaków jest zgodnych z ASCII

• 256 pierwszych –ISO 8859-1

(2)

UTF-8

• Pewne sekwencje bajtów posiadają

specjalne znaczenie w róŜnych systemach operacyjnych. Unicode moŜe być

niebezpieczny!

• UTF (UCS Transformation Format)

• UTF-8 : 1 bajt dla ASCII,2 bajty dla znaków 8-bitowych i 3 bajty dla pozostałych

Hierarchia klas strumieniowych obejmuje tzw. klasy przedmiotowe to jest związane z konkretnym źródłem lub odbiorcą danych (tablica, łańcuch znaków, plik,) potok...)* oraz klasy przetwarzające (dekoracyjne), których zadanie polega na dostarczeniu dodatkowych uŜytecznych własności (nazywane teŜ filtrami).

Przykładem klasy dekoracyjnej jest DataInputStream umoŜliwiająca odczyt ze strumienia danych wszystkich podstawowych typów (readByte(), readFloat() ...) i stringów. „Odwrotne” usługi oferuje DataOutputStream.

* Nazywane równieŜ strumieniami ujścia danych

Klasy przedmiotowe i przetwarzające

Typy strumieni wejściowych

Interfejs dla klas dekoracyjnych FilterInputStream

Z potoku PipedInputStream

Z pliku FileInputStream

Ze String-u StringBufferInputStream

Z bufora w pamięci.

ByteArrayInputStream

Typy strumieni wyjściowych

Interfejs dla klas dekoracyjnych FilterOutputStream

Do potoku PipedOutputStream

Do pliku FileOutputStream

Uwaga! Nie ma!

String jest niezmienny

>>StringBufferOutputStream<<

Do bufora w pamięci.

ByteArrayOutputStream

(3)

Wejściowe klasy „dekoracyjne”

dekompresja InflaterInputStream

Pozwalają na

„zwracanie”

odczytanego znaku PushbackInputStream

PushbackReader

Zapewniają numerację wierszy

LineNumberInputStream LineNumberReader

Zapewniają buforowanie BufferedInputStream

BufferedReader

Pozwalają na

odczytywanie typów prostych.

DataInputStream

Wyjściowe klasy „dekoracyjne”

kompresja DeflaterOutputStream

Do wypisywania typów prostych w czytelny sposób)

PrintStream PrintWriter

Zapewniają buforowanie BufferedOutputStream

BufferedWriter

Pozwala na zapisywanie typów prostych.

writeFloat() ...

DataOutputStream

Łańcuchy strumieni

• Strumienie zwiększają swoje moŜliwości gdy wyjście jednego strumienia połączymy do wejścia innego tworząc łańcuch.

Przykład

File f = new File („phrases.utf”) ; FileReader r = new FileReader(f);

BufferedReader in = new BufferedReader(r);

String line = in.readLine() ; //unexpected result!

// System.getProperty(„file.encoding”) ;

(4)

Readers & Writers

• Z uwagi na operowanie kodami Unicode

(internacjonalizacja) biblioteki we/wy w języku Java uległy w wersji 1.1 gruntownej modyfikacji (rozbudowie)

• Są sytuacje gdy w programie uŜywa się zarówno klas bajtowych jak i znakowych wówczas

poŜyteczne mogą być klasy konwerujące:

• InputStream    InputStreamReader Reader

• OutputStream     OutputStreamWriter    Writer

Przykład again

File f = new File („phrases.utf”) ;

FileInputStream is = new FileInputStream(f);

InputStreamReader in =

new InputStreamReader (is, „UTF8”);

BufferedReader in = new BufferedReader(in);

String line = in.readLine() ; // is ok

„Odpowiedniki znakowe” klas przedmiotowych

PipedWriter PipedOutputStream

PipedReader PipedInputStream

CharArrayWriter ByteArrayOutputStream

CharArrayReader ByteArrayInputStream

StringWriter Brak odpowiednika

StringReader StringBufferInputStream

FileWriter FileOutputStream

FileReader FileInputStream

Writer OutputStream

Reader InputStream

Odpowiedniki znakowe” klas dekoracyjnych

PushBackReader PushBackInputStream

StreamTokenizer(Reader) StreamTokenizer

LineNumberReader LineNumberInputStream

PrintWriter PrintStream

DataInputStream ! DataInputStream

BufferedWriter BufferedOutputStream

BufferedReader BufferedInputStream

FilterWriter FilterOutputStream

FilterReader FilterInputStream

(5)

RandomAccessFile

• Pliki zbudowane z rekordów o znanej długości, do których uzyskuje się dostęp przez zmianę połoŜenia wskaźnika (seek()) „obsługiwane” są przez klasę

RandomAccessFile

Kolekcje

W wielu programach deklaracje typu:

MyObject myReference;

są uprawnione, jednak często zwłaszcza przy bardziej skomplikowanych programach nowe obiekty są kreowane w oparciu o pewne kryteria znane dopiero w czasie wykonania. Wcześniej nie jest znana ani liczba, a niekiedy nawet typ

potrzebnych obiektów.

W pewnym stopniu problem rozwiązuje

wbudowany w Javie typ array.

(6)

Tablica (Array) to po prostu sekwencja obiektów lub wartości typu prostego opatrzona wspólną nazwą.

Wszystkie elementy tablicy muszą być tego samego typu! Tablice definiujemy uŜywając nawiasów

prostokątnych []:

int[] a1; // zapis naturalny: a1 jest typu tablica int

lub

int a1[]; // styl języka C

Alokacja elementów tablicy

Nie zaalokowano jeszcze miejsca dla tablicy, a1 jest referencją do tablicy.

MoŜna to zrobić za pomocą wyraŜenia inicjalizującego:

int[] a1 = { 1, 2, 3, 4, 5 };

int[] a1 = new [11] ; // The primitives inside //the array are automatically initialized to zero Weeble[] a;

a = new Weeble[] { new Weeble(), new Weeble() };

Tablice posiadają nieodłączne pole składowe length, które moŜna odczytywać (ale nie zmieniać) wskazujące ile elementów jest w tablicy (a1.length jest równe 5). Indeks tablicy zmienia się od 0 do length-1. Wyjście poza ten zakres generuje błąd czasu wykonania (exception).

Kontrola indeksów tablic jest jednym z powodów mniejszej efektywności środowiska Java, pozwala

natomiast uniknąć wielu nieprzewidzianych i trudnych do wykrycia błędów programu.

Uwaga: tablica jest obiektem, nawet jeśli elementy tablicy są typu prostego.

Object[] a; // uninitialized variable

Object[] b = new Object[5]; // Null references for(int i; i < b.length; i++)

b[i] = new Object() ;

(7)

Tablice wielowymiarowe

int[][] a1 = { { 1, 2, 3, }, { 4, 5, 6, }, };

int[][][] a2 = new int[2][2][4];

Klasa Arrays

W pakiecie java.util znajduje się klasa Arrays, w której zdefiniowano szereg uŜytecznych metod statycznych. Są to cztery następujące przeciąŜone (dla typów prostych i Object) grupy:

equals( ), - do porównania zawartości tablic;

fill( ), do wypełnienia tablicy określoną wartością (taka sama) sort( ), do sortowania tablic;

binarySearch( ), wyszukanie elementu w posortowanej tablicy.

Ponadto metoda asList( ) umieszcza elementy tablicy w kontenerze List.

W klasie System zdefiniowano uŜyteczną metodę słuŜącą do kopiowania zawartości tablic:

void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

Kopiowanie zawartości tablic

int[] i = new int[7];

int[] j = new int[10];

Arrays.fill(i, 47);

Arrays.fill(j, 99);

System.arraycopy(i, 0, j, 0, i.length); // "j = //[47, 47, 47, 47, 47, 47, 47, 99, 99, 99]„

Oczywiście kaŜde naruszenie zakresu indeksów spowoduje wygenerowanie wyjątku.

Dla tablic obiektów kopiowane są tylko referencje nie same obiekty!

Przykład

(8)

Porównywanie tablic metoda Arrays.equals()

Aby tablice były równe musza mieć taką samą liczbę elementów oraz odpowiadające sobie elementy muszą być równe w sensie metody equals() typu tych

elementów, a dla typów prostych w sensie metody equals() odpowiednich typów opakowujących.

Porównywanie elementów tablic.

Jednym z podstawowych celów projektowania

programów jest „separacja rzeczy, które się zmieniają od tych, które są niezmienne”.

Jako przykład rozwaŜmy problem sortowania. To co jest niezmienne to sam algorytm sortowania, natomiast zmienny jest sposób porównywania obiektów. Stąd zamiast wbudowywać te sposoby porównywania w róŜne procedury sortowania stosujemy rozwiązanie, w którym niezmienny fragment kodu wywołuje zmienną część (technika callback).

Java oferuje dwa sposoby porównywania obiektów.

Pierwszy oparty jest na metodzie wprowadzonej do klasy drogą implementacji interfejsu java.lang.Comparable. Interfejs ten definiuje tylko jedną metodę: int compareTo(Object o).

Metoda ta porównuje przekazany argumentem obiekt i zwraca wartość mniejszą od zera jeśli bieŜący obiekt jest mniejszy od argumentu, zero jeśli oba obiekty są równe i wartość dodatnią jeśli obiekt jest większy od argumentu.

Od implementacji metody compareTo() zaleŜy „co to oznacza, Ŝe obiekt jest mniejszy, równy, większy”. Jeśli klasa

implementuje interfejs Comparable moŜna posortować tablicę obiektów a:

2 sposoby porównywania

public class CompType implements Comparable { int i; int j;

public CompType(int n1, int n2) { i = n1;

j = n2;

}

public String toString() {

return "[i = " + i + ", j = " + j + "]"; } public int compareTo(Object rv) { int rvi = ((CompType)rv).i;

return (i < rvi ? -1 : (i == rvi ? 0 : 1));

} }

(9)

CompType[] a = new CompType[12] ; // …

Arrays.sort(a);

Co jeśli klasa nie implementuje interfejsu Comparable, lub implementacja nas nie satysfakcjonuje? Rozwiązaniem moŜe być zastosowanie wzorca projektowego strategy, zgodnie z którym zmienny kod umieszczany jest w oddzielnej klasie (strategy object). Następnie do niezmiennej części algorytmu przekazujemy ten obiekt, który umoŜliwia rozwiązanie problemu. Zgodnie z tym wzorcem moŜemy zaprojektować róŜne sposoby porównywania obiektów i uzupełniać nimi niezmienny algorytm. Przy sortowaniu definiujemy klasy implementujące interfejs Comparator, w którym zdefiniowano metody: compare( ) i equals( ). PoniewaŜ implementację metody equals( ) wszystkie klasy dziedziczą po klasie Object niezbędne jest jedynie zdefiniowanie metody compare( ).

2 sposób

Podsumowując, sortowanie tablic zawierających obiekty jest moŜliwe jeśli implementują one interfejs Comparable lub posiadają skojarzony z nim

Comparator.

W obecnych wersjach API języka Java (od 1.2) klasa String implementuje interfejs Comparable co umoŜliwia leksykograficzne sortowanie tablic stringowych (z uwzględnieniem wielkości liter).

Jeśli ta reguła sortowania nie jest adekwatna do danego zastosowania to definiujemy własną klasę komparatora np.

public class AlphabeticComparator implements Comparator { public int compare(Object o1, Object o2) {

String s1 = (String)o1;

String s2 = (String)o2;

return s1.toLowerCase().compareTo(s2.toLowerCase());

} }

(10)

Searching a sorted array

Once an array is sorted, you can perform a fast search for a particular item by using Arrays.binarySearch( ). However, it’s very important that you do not try to use binarySearch( ) on an unsorted array; the results will be unpredictable.

Arrays.binarySearch( ) produces a value greater than or equal to zero if the search item is found. Otherwise, it produces a negative value representing the place that the element should be inserted if you are maintaining the sorted array by hand. The value produced is

-(insertion point) - 1

Podsumowując tablice są podstawowym i najefektywniejszym sposobem przechowywania grupy obiektów (i jedynym sposobem dla typów prostych). Jeśli jednak nie jest znana z góry liczba obiektów lub potrzebujemy bardziej

wyrafinowanego sposobu przechowywania obiektów naleŜy skorzystać z biblioteki klas kontenerowych (Collections).

Pakiet utilities zawiera zbiór klas kontenerowych znanych jako kolekcje. Kontenery te (List, Set, Map) mogą

przechowywać wyłącznie obiekty i traktują je właśnie jako instancje klasy Object. Wartości typu prostego naleŜy przed umieszczeniem w kontenerze „opakować” (klasy Integer, Double, etc.).

Podsumowanie

Cytaty

Powiązane dokumenty

W przestrzeni dyskretnej w szczególności każdy jednopunktowy podzbiór jest otwarty – dla każdego punktu możemy więc znaleźć taką kulę, że nie ma w niej punktów innych niż

Spoglądając z różnych stron na przykład na boisko piłkarskie, możemy stwierdzić, że raz wydaje nam się bliżej nieokreślonym czworokątem, raz trapezem, a z lotu ptaka

Bywa, że każdy element zbioru A sparujemy z innym elementem zbioru B, ale być może w zbiorze B znajdują się dodatkowo elementy, które nie zostały dobrane w pary.. Jest to dobra

Następujące przestrzenie metryczne z metryką prostej euklidesowej są spójne dla dowolnych a, b ∈ R: odcinek otwarty (a, b), odcinek domknięty [a, b], domknięty jednostronnie [a,

nierozsądnie jest ustawić się dziobem żaglówki w stronę wiatru – wtedy na pewno nie popłyniemy we właściwą stronę – ale jak pokazuje teoria (i praktyka), rozwiązaniem

W przestrzeni dyskretnej w szczególności każdy jednopunktowy podzbiór jest otwarty – dla każdego punktu możemy więc znaleźć taką kulę, że nie ma w niej punktów innych niż

Zbiór liczb niewymiernych (ze zwykłą metryką %(x, y) = |x − y|) i zbiór wszystkich.. Formalnie:

też inne parametry algorytmu, często zamiast liczby wykonywanych operacji rozważa się rozmiar pamięci, której używa dany algorytm. Wówczas mówimy o złożoności pamięciowej;