Proz S5 id 402995 Nieznany

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 1

5. Strumienie wej

ś

cia – wyj

ś

cia

5.1 Klasy strumieni WE-WY
5.2 Korzystanie ze strumieni
5.3 Serializacja obiektów
5.4 Pliki o dost

ę

pie swobodnym

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 2

5.1 Klasy strumieni WE-WY

Klasy w pakiecie

java.io

słu

żą

do obsługi

strumieni wej

ś

cia - wyj

ś

cia

(które mog

ą

zosta

ć

otwarte dla

pliku, pami

ę

ci, gniazdka,

itd., a nast

ę

pnie

odczytane lub zapisane sekwencyjnie).

Strumień danych

ODCZYT

Ź

ródło

Strumień danych

ZAPIS

Cel

Bez wzgl

ę

du na rodzaj strumienia sposób współpracy jest ten sam:

Odczyt

Zapis



OTWÓRZ



while JEST_INFORMACJA

ODCZYT


ZAMKNIJ_STRUMIEŃ



OTWÓRZ



while JEST_INFORMACJA

ZAPIS


ZAMKNIJ_STRUMIEŃ

Podział klas we-wy w

java.io

- ze wzgl

ę

du

na dane

na których operuj

ą

:



znakowe strumienie

i



bajtowe strumienie.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 3

1) Strumienie znakowe

Reader, Writer

to abstrakcyjne klasy bazowe dla strumieni znakowych

(zawieraj

ą

implementacje cz

ęś

ci metod).

Klasy pochodne od

Reader

i

Writer

:

- dla odczytu/zapisu danych (na szarym tle)
- wykonuj

ą

ce pewne przetwarzanie (na białym tle).

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 4

2) Strumienie bajtowe

InputStream, OutputStream

- bazowe klasy dla odczytu/zapisu 8-

bitowych

binarnych

danych.

Klasy pochodne

od

InputStream, OutputStream

:

- dla odczytu/zapisu danych (na szarym tle)
- wykonuj

ą

ce pewne przetwarzanie (na białym tle).

-

ObjectInputStream, ObjectOutputStream

- klasy przeznaczone do

deserializacji i serializacji obiektu

.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 5

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 6

3) Klasa

Reader

Klasa

Reader

zawiera metody dla

odczytu

znaków i tablic

znaków

.

// Deklaracja klasy i jej składowych

public abstract class Reader extends Object {

// Pole dla synchronizacji dost

ę

pu

protected Object lock;

// Zamiast obiektu klasy

Reader

synchronizacj

ę

dost

ę

pu w

ą

tków do obiektu strumieniowego zapewni jego pole.

// Konstruktory

protected Reader();

// Konstruktor strumienia znakowego dla odczytu -

// synchronizacja na obiekcie klasy.

protected Reader(Object lock);

// - synchronizacja na zadanym obiekcie.

// Metody steruj

ą

ce stanem i informuj

ą

ce o stanie strumienia

abstract void close();

// Zamyka strumień.

void mark (int readAheadLimit);

// Wstawia znacznik w aktualnej pozycji.

boolean markSupported();

//Informuje czy strumień posiada operację mark

boolean ready ();

// Czy strumień jest gotowy do odczytu

.

void reset ();

// Powróć do ostatniego znacznika.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 7

long skip (long n);

// Pomiń n znaków.

// 3 wersje metody read()

int read ();

// Czytaj pojedynczy znak.

int read (char[] cbuf);

// Wczytaj znaki do tablicy.

abstract int read (char[] cbuf, int off, int len);

// Wczytaj znaki do tablicy w

// określone miejsce

.

}

4) Klasa

InputStream

Klasa

InputStream

posiada metody dla odczytu bajtów i tablic bajtów.

// Deklaracja klasy i jej składowych.

public abstract class InputStream extends Object {

public InputStream();

// Konstruktor

// 3 wersje metody read()

public abstract int read() throws IOException;

// Metoda abstrakcyjna

public int read(byte[] b) throws IOException;

// 2

public int read(byte[] b, int offset, int length) throws IOException;

// 3

// Wersje 2 i 3 s

ą

zdefiniowane.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 8

public void close() throws IOException;

// Zamyka strumie

ń

i zwalnia

// jego zasoby - metoda musi by

ć

nadpisana.

//
// Sterowanie pozycj

ą

znacznika w strumieniu.

public long skip(long n) throws IOException;

// Przeskoczy

ć

pewn

ą

// liczb

ę

bajtów – metoda musi by

ć

nadpisana

public int available() throws IOException;

// Zwraca liczb

ę

bajtów, które

// mog

ą

zosta

ć

odczytane bez blokowania strumienia - metod

ę

trzeba

// nadpisa

ć

.

public void reset() throws IOException;

// Powraca do ostatniego

// znacznika - metoda musi zosta

ć

nadpisana w klasach pochodnych.

public void mark(int readlimit);

// Wstawia znacznik i ustawia limit

// odczytu - metoda musi zosta

ć

nadpisana w klasach pochodnych

public boolean markSupported();

// Sprawdza czy istniej

ą

mark()

i

reset()

}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 9

5) Klasa

Writer

Klasa

Writer

posiada metody dla zapisu znaków i tablic znaków.

public abstract class Writer extends Object {

// Konstrukcja i synchronizacja

protected Objeck lock;

// Zamiast obiektu synchronizację zapewni jego pole

.

protected Writer();

// Konstrukcja strumienia samo-synchronizowanego.

protected Writer(Object lock

);//Konstrukcja strumienia synchronizowanego

// przekazanym obiektem.

// Sterowanie stanem

abstract void close();

// Wykonaj flush() i zamknij strumień

.

abstract void flush();

// Zapisz wszystko co jest w buforze do strumienia.

// 5 wersji metody

write()

void write(char[] cbuf);

// Zapisz tablicę znaków.

abstract void write(char[] cbuf, int off, int len);

// Zapisz część tablicy

void write (int c);

// Zapisz pojedynczy znak.

void write(String str);

// Zapisz string.

void write(String str, int off, int len);

// Zapisz część string-a.

}

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 10

6) Klasa

OutputStream

Klasa

OutputStream

posiada metody zapisu dla bajtów.

public abstract class OutputStream extends Object {

// Konstruktor

public OutputStream();

// Sterowanie stanem

void close();

// Zamknij strumień, zwolnij jego zasoby systemowe.

void flush();

// Wypełnij strumień i wypisz wszystko z bufora.

// 3 wersje metody write()

void write (byte[] b);

// Wypisz liczbę (b.length) bajtów z tablicy b

.

void write (byte[] b, int off, int len);

// Wypisz liczbę (len) bajtów z tablicy.

abstract void write (int b);

// Wypisz podany bajt.

}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 11

7) Otwarcie i zamkni

ę

cie strumienia

Otwarcie strumienia:



automatycznie w chwili utworzenia obiektu strumienia typu

Reader,

Writer, InputStream, OutputStream

.


Zamkni

ę

cie strumienia:



wykonanie metody

close

strumienia, lub poleganie na "

Garbage

Collector

".

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 12

5.2 Korzystanie ze strumieni

1) Strumienie plikowe (

FileReader, FileWriter, FileInputStream,

FileOutputStream

)

Mo

ż

na utworzy

ć

strumie

ń

plikowy:



dla pliku przekazanego w postaci napisu (

string)

,



dla obiektu klasy

File

lub



dla obiektu klasy

FileDescription

.

Przykład.

Wykorzystanie klas

FileReader

i

FileWriter

dla skopiowania

zawarto

ś

ci pliku

plikWE.txt

do pliku

plikWY.txt

.

import java.io.*;
public class PrzykladKopiowaniaPlikow {
public static void main(String[] args) throws IOException {

File inputFile = new File("plikWE.txt");

// Obiekt klasy File

File outputFile = new File("plikWY.txt");

// Obiekt klasy File

FileReader in = new FileReader(inputFile);

// Utwórz "FileReader-a"

FileWriter out = new FileWriter(outputFile);

// Utwórz "FileWriter-a"

int c;

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 13

while ((c = in.read()) != -1)

out.write(c);

// Odczyt z pliku we. i zapis do pliku wy.

in.close();

// Zamknij plik wejściowy

out.close();

// Zamknij plik wyjściowy

}
}

2) Pochodne klasy strumieniowe w

java.io

Typ we-wy

Klasy strumieni

Opis

CharArrayReader
CharArrayWriter
ByteArrayInputStream
ByteArrayOutputStream

Strumieniowy odczyt/zapis z /do tablicy
w pami

ę

ci programu.

Pami

ęć

StringReader
StringWriter
StringBufferInputStream

StringReader

- odczyt znaków ze

String

-

u w pami

ę

ci.

StringWriter

- zapis

znaków z wewn

ę

trznego

StringBuffer

do

String

-a.

StringBufferInputStream

-

odczyt bajtów ze

StringBuffer

.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 14

Plik

FileReader
FileWriter
FileInputStream
FileOutputStream

Odczyt/zapis z/do pliku zewn

ę

trznego.

Potok

PipedReader
PipedWriter
PipedInputStream
PipedOutputStream

Potoki przeprowadzaj

ą

wyj

ś

cie z

jednego strumienia w wej

ś

cie dla

drugiego.

Konkate-
nacja

znakowe - N/A
SequenceInputStream

Ł

ą

czy wiele strumieni wej

ś

ciowych w

jeden.

Serializacja
obiektu

znakowe - N/A
ObjectInputStream
ObjectOutputStream

Utrwalenie stanu obiektu i odczytanie
wcze

ś

niej utrwalonego stanu obiektu.


background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 15

Konwersja
danych

znakowe - N/A
DataInputStream
DataOutputStream

Odczyt/zapis prostych typów danych
do formatu niezale

ż

nego od maszyny.

Zliczanie

LineNumberReader
LineNumberInputStream

Zlicza liczb

ę

wierszy podczas odczytu.

Podgl

ą

d

wprzód

PushbackReader
PushbackInputStream

Strumienie wej

ś

ciowe z buforem

stosowym - umo

ż

liwia podgl

ą

d wprzód.

Drukowanie

PrintWriter
PrintStream

Zawieraj

ą

metody dla drukowania.

Buforowanie

BufferedReader
BufferedWriter
BufferedInputStream
BufferedOutputStream

Buforowane strumienie we/wy.


5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 16

Filtracja

FilterReader
FilterWriter
FilterInputStream
FilterOutputStream

Klasy abstrakcyjne definiuj

ą

ce interfejs

dla strumieni filtrujacych -
wzmacniaj

ą

cych odczyt lub zapis.

Konwersja
pomi

ę

dzy

bajtami a
znakami

InputStreamReader
OutputStreamWriter

InputStreamReader

- odczytuje bajty z

InputStream

i zamienia je na znaki.

OutputStreamWriter

- konwertuje znaki

na bajty i zapisuje je w

OutputStream

.

System.getProperty("file.encoding")

- daje

domy

ś

lny sposób kodowania znaków.

Własny system kodowania znaków:

Kodowanie 16-bitowe znaków odbywa si

ę

według domy

ś

lnego systemu:

System.getProperty("file.encoding")

;

// Uzyskanie informacji o domy

ś

lnym

// sposobie kodowania znaków.

Własny sposób kodowania:



utworzy

ć

obiekt klasy

OutputStreamWriter

pracuj

ą

cy na strumieniu

FileOutputStream

i poda

ć

sposób kodowania.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 17

3) Strumienie "potokowe - przesyłowe" (

PipedReader, PipedWriter

)

Niech klasa posiada metody słu

żą

ce do przetwarzania tekstów, takie jak

sortowanie słów i odwracanie słów.

Bez strumieni przesyłowych

wyniki

po

ś

rednie dla kolejnych wywoła

ń

tych metod zapisywane musiałyby by

ć

w pami

ę

ci programu lub pliku, np.:


Przy istnieniu

strumieni przesyłowych

wyj

ś

cie z jednej metody mo

ż

e

bezpo

ś

rednio stanowi

ć

wej

ś

cie dla drugiej metody:

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 18

Przykład.

U

ż

ycie klas

PipedReader

i

PipedWriter

dla poł

ą

czenia wej

ś

cia i wyj

ś

cia

pewnych metod

reverse

i

sort

w celu przetworzenia listy słów.


Mo

ż

liwe b

ę

dzie poł

ą

czone wywołanie obu metod:

// Utworzenie obiektu strumienia wej

ś

ciowego:

FileReader words = new FileReader("words.txt");

// Przetwarzanie potokowe i przekazanie wyniku - obiektu klasy

Reader:

Reader processedWords = reverse(sort(reverse(words)));

W tym celu wymagane s

ą

odpowiednie definicje

reverse()

i

sort(

).

Potok

W ka

ż

dej z tych metod zostan

ą

utworzone i poł

ą

czone ze sob

ą

dwa

obiekty: (1) obiekt klasy

PipedReader

"osadzony" zostaje na (2) obiekcie

klasy

PipedWriter

- wszystko to co zostanie zapisane do obiektu klasy

PipedWriter

mo

ż

e zosta

ć

odczytane przez obiekt klasy

PipedReader

.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 19

// Definicja metody

reverse()

mo

ż

e by

ć

nast

ę

puj

ą

ca:

public static Reader reverse(Reader source) throws IOException {

// Buforuj strumie

ń

wej

ś

ciowy b

ę

d

ą

cy argumentem metody

BufferedReader in = new BufferedReader(source);

// source

 in

// Utwórz i powi

ąż

ze sob

ą

2 obiekty "potokowe"

PipedWriter pipeOut = new PipedWriter();

// 1-szy obiekt

PipedReader pipeIn = new PipedReader(pipeOut);

// 2-gi obiekt:

// pipeOut

 pipeIn

// Strumie

ń

dla wydruku przeka

ż

e dane do

pipeOut :

PrintWriter out = new PrintWriter(pipeOut);

// out

 pipeOut

// Wła

ś

ciwe przetwarzanie odb

ę

dzie si

ę

w nowym w

ą

tku

new ReverseThread(out, in).start();

// Wątek do odwracania kolejności:

// in

 (odwróć)  out

return pipeIn;

// Metoda zwraca obiekt potokowy

pipeIn

typu

//

PipedReader

powi

ą

zany ze stworzonym obiektem

pipeOut

.

}

Metoda

sort

jest prawie identyczna z

reverse

z t

ą

ż

nic

ą

,

ż

e tworzy i

woła obiekt pewnej klasy

SortThread

.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 20

"Opakowanie" strumienia

W powy

ż

szym przykładzie metoda

reverse

zawiera m.in. dwie dalsze

instrukcje powi

ą

zania obu obiektów strumieni potokowych z dalszymi

strumieniami (typu

BufferedReader

i

PrintWriter

), w celu skorzystania z

dogodnych metod tych klas do odczytu i zapisu wierszy znaków.

BufferedReader in = new BufferedReader(source);

// source

 in

Nast

ę

puje tu otwarcie strumienia typu

BufferedReader

dla

ź

ródła, które

jest

strumieniem

wej

ś

ciowym,

jednak

o

innym

typie.

W

ą

tek

przetwarzaj

ą

cy czyta z obiektu typu

BufferedReader

, który z kolei czyta

ze

strumienia

ź

ródłowego.

Dzi

ę

ki

"opakowaniu"

ź

ródła

klas

ą

BufferedReader

w

ą

tek mo

ż

e zastosowa

ć

metod

ę

readLine

tej klasy.

...

PrintWriter out = new PrintWriter(pipeOut);

// out

 pipeOut

Podobnie obiekt typu

PipedWriter

zostaje opakowany przez obiekt typu

PrintWriter

i program mo

ż

e zastosowa

ć

dogodn

ą

metod

ę

println

klasy

PrintWriter

.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 21

4) Ł

ą

czenie (konkatenacja) plików (

SequenceInputStream

)

Przykład.

U

ż

ycie klasy

SequenceInputStream

dla poł

ą

czenia plików w

jeden strumie

ń

odpowiednio do ich kolejno

ś

ci w wywołaniu programu.

// Klasa główna programu:

import java.io.*;
public class PolaczenieStrumieni {
public static void main(String[] args) throws IOException {

// Najpierw tworzony jest obiekt klasy

ListaPlikow

o nazwie

mylist

// inicjalizowany list

ą

plików podan

ą

w linii wywołania programu.

// Klasa

ListPlikow

musi implementowa

ć

interfejs

Enumeration

, czyli

// posiada

ć

m.in. metod

ę

nextElement

().

ListaPlikow mylist = new ListaPlikow(args);

// Konstruktor klasy

SequenceInputStream

inicjalizuje obiekt

// sekwencj

ą

obiektów typu

InputStream

tworzonych wywołaniami

//metody

nextElement

dla obiektu klasy implementuj

ą

cej

Enumeration

SequenceInputStream str = new SequenceInputStream(mylist);
int bajt;

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 22

// Metoda

main

po utworzeniu obiektu klasy

SequenceInputStream

,

// odczytuje z niego bajt po bajcie.

while ((bajt = str.read()) != -1)
System.out.write( bajt );
str.close();
}
}

Klasa

ListaPlików

mo

ż

e by

ć

zdefiniowana nast

ę

puj

ą

co:

import java.util.*;
import java.io.*;
public class ListPlikow implements Enumeration {
private String[] listOfFiles;
private int current = 0;
public ListPlikow(String[] listOfFiles) {
this.listOfFiles = listOfFiles;
}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 23

public boolean hasMoreElements() {
if (current < listOfFiles.length)
return true;
else
return false;
}

// Metoda

nextElement

klasy

ListaPlikow

tworzy strumie

ń

typu

// FileInputStream

dla nast

ę

pnej nazwy pliku na li

ś

cie i zwraca ten

// obiekt. Je

ś

li lista nazw wyczerpie si

ę

to zwracane jest

null

.

public Object nextElement() {

// Zwróci obiekt typu

FileInputStream

InputStream in = null;
if (!hasMoreElements() )
throw new NoSuchElementException("Brak dalszych plików.");
else {
String nextElement = listOfFiles[current];
current++;
try {
in = new FileInputStream(nextElement);

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 24

}
catch (FileNotFoundException e) {
System.err.println("ListaPlikow:Nie można otworzyć " +
nextElement);
}
}
return in;
}
}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 25

5) Strumienie filtruj

ą

ce

(FilterInputStream, FilterOutputStream,

FilterReader, FilterWriter

)

Strumie

ń

filtruj

ą

cy wymaga doł

ą

czenia do niego innego (obrabianego)

strumienia. Metoda

read

strumienia filtruj

ą

cego wczytuje dane z

podległego strumienia, filtruje je i przekazuje jako swój wynik.
Metoda

write

filtruje przekazywane jej dane i zapisuje tak przetworzone

dane do podległego strumienia.
W pakiecie

java.io

zdefiniowano bajtowe klasy bazowe

FilterInputStream

i

FilterOutputStream

i szereg ich klas pochodnych:

DataInputStream, DataOutputStream

BufferedInputStream , BufferedOutputStream

LineNumberInputStream

PushbackInputStream

PrintStream

(strumie

ń

wyj

ś

ciowy)

W pakiecie

java.io

wyst

ę

puje jedynie jedna klasa pochodna od klasy

znakowego strumienia

FilterReader

:

PushbackReader

.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 26

Utworzenie strumienia filtruj

ą

cego

Np. doł

ą

czenie standardowego strumienia wej

ś

ciowego do strumienia

filtruj

ą

cego i "opakowanie" klas

ą

BufferedReader

dla uzyskania metody

readLine()

:

BufferedReader d = new BufferedReader (new

DataInputStream(System.in));

String input;
while ((input = d.readLine()) != null) {
...

// wykonuje przetwarzanie

}

Przykład.

Wykorzystanie klas

DataInputStream

i

DataOutputStream

w

celu formatowania odczytu i zapisu danych w postaci kolumn
przedzielonych znakiem tabulacji. Kolumnami s

ą

: cena, liczba zamówie

ń

,

opis towaru - zapisane binarnie.

// (1) Najpierw obiekt typu

DataOutputStream

zostaje doł

ą

czony do

// obiektu klasy

FileOutputStream

, który słu

ż

y do zapisu do pliku

//

rachunek1.txt

:

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 27

DataOutputStream out = new DataOutputStream(
new FileOutputStream("rachunek1.txt"));

// (2) Program korzysta z metody

write

klasy

DataOutputStream

aby

// zapisa

ć

do pliku dane wyst

ę

puj

ą

ce w tablicach odpowiednio

// do ich typów:

for (int i = 0; i < prices.length; i ++) {

// Tablica

prices

zawiera dane

out.writeDouble(prices[i]); //
out.writeChar('\t');
out.writeInt(units[i]);
out.writeChar('\t');
out.writeChars(descs[i]);
out.writeChar('\n');
}
out.close();

// (3) Teraz otworzymy strumie

ń

typu

DataInputStream

dla wła

ś

nie

// co zapisanego pliku:

DataInputStream in = new DataInputStream(
new FileInputStream("rachunek1.txt"));

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 28

// (4)

DataInputStream

te

ż

musi by

ć

doł

ą

czony do innego strumienia - w

// tym przypadku do

FileInputStream

- aby odczyta

ć

dane z pliku.

// (5)Teraz dane wczytywane s

ą

przez specjalizowane metody

readXxxx

// klasy

DataInputStream:

try {
while (true) {

//Teoretycznie bezwarunkowa p

ę

tla ko

ń

czona wyj

ą

tkiem

price = in.readDouble();
in.readChar();

// usuwa znak tabulacji

unit = in.readInt();
in.readChar();

// usuwa znak tabulacji

char chr;
desc = new StringBuffer(20);
char lineSep = System.getProperty("line.separator").charAt(0);
while ((chr = in.readChar() != lineSep) {
desc.append(chr);
}
System.out.println("Zamówiono " + unit + " jednostek "
+ desc + " po cenie $" + price);

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 29

total = total + unit * price;
}
}
catch (EOFException e) { }
System.out.println("SUMA: $" + total);
in.close();

Uwaga:

zwykle p

ę

tla odczytu danych wygl

ą

da nast

ę

puj

ą

co:

while ((input = in.read()) != null) {
. . .
}

Jest to mo

ż

liwe dla klas, które mog

ą

symbolem

null

przekaza

ć

osi

ą

gni

ę

cie ko

ń

ca pliku. Wiele metod klasy

DataInputStream

nie mo

ż

e

tak sygnalizowa

ć

ko

ń

ca pliku, gdy

ż

ka

ż

da warto

ść

mo

ż

e by

ć

poprawn

ą

dan

ą

, np. -1. Dlatego te

ż

metody

read

klasy

DataInputStream

zgłaszaj

ą

w tym celu wyj

ą

tek

EOFException

.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 30

Definiowanie własnych strumieni filtruj

ą

cych

1. Utworzy

ć

klasy pochodne od

FilterInputStream

i

FilterOutputStream

-

zwykle współpraca z plikami ma dualny charakter.

2. Nadpisa

ć

metody

read

i

write

w razie potrzeby.

Przykład.

Zdefiniowanie pary klas pochodnych od

FilterInputStream

i

FilterOutputStream

korzystaj

ą

cych z klasy sprawdzaj

ą

cej sum

ę

kontroln

ą

odczytywanych i zapisywanych danych.
Program

CheckedIODemo

obejmuje 4 klasy i 1 interfejs:

klasy

pochodne

strumieni

filtruj

ą

cych

-

CheckedOutputStream,

CheckedInputStream

interfejs

Checksum

i klasa

Adler32

dla obliczania sumy kontrolnej,

klasa główna programu

CheckedIODemo

z metod

ą

main

.

// Konstruktor klasy

CheckedOutputStream

:

public CheckedOutputStream(OutputStream out, Checksum cksum) {
super(out);

// Zainicjalizuj podobiekt dziedziczony

this.cksum = cksum;

// Zapisz sum

ę

kontroln

ą

}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 31

Argumentami

konstruktora

s

ą

:

obiekt

strumienia

wyj

ś

ciowego

OutputStream

podlegaj

ą

cy filtrowaniu i obiekt klasy

Checksum

, który jest w

stanie obliczy

ć

sum

ę

kontroln

ą

.

W klasie

CheckedOutputStream

nadpisano wszystkie trzy wersje metody

write

klasy

FilterOutputStream

:

public void write(int b) throws IOException {
out.write(b);
cksum.update(b);
}
public void write(byte[] b) throws IOException {
out.write(b, 0, b.length);
cksum.update(b, 0, b.length);
}
public void write(byte[] b, int off, int len) throws IOException {
out.write(b, off, len);
cksum.update(b, off, len);
}

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 32

Celem metod

write

jest zapis danych do strumienia wyj

ś

ciowego i

modyfikacja sumy kontrolnej.

Klasa

CheckedInputStream

jest podobna do klasy

CheckedOutputStream

.

Jej jedyny konstruktor to:

public CheckedInputStream(InputStream in, Checksum cksum) {
super(in);
this.cksum = cksum;
}

W klasie

CheckedInputStream

nadpisano wszystkie trzy wersje metody

read

klasy bazowej

FilterInputStream

:

public int read() throws IOException {
int b = in.read();
if (b != -1) {
cksum.update(b);
}
return b;
}

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 33

public int read(byte[] b) throws IOException {
int len;
len = in.read(b, 0, b.length);
if (len != -1) { cksum.update(b, 0, b.length); }
return len;
}
public int read(byte[] b, int off, int len) throws IOException {
len = in.read(b, off, len);
if (len != -1) { cksum.update(b, off, len); }
return len;
}

Metody

read

wczytuj

ą

dane ze strumienia wej

ś

ciowego i je

ś

li wczytano

dan

ą

to nast

ą

pi modyfikacja sumy kontrolnej.

Interfejs

Checksum

obejmuje m.in. metody

getValue

i

update

przeznaczone dla pobrania i modyfikowania warto

ś

ci sumy kontrolnej.

Suma jest obliczana krok po kroku dla danych całego strumienia. Np.
klasa

Adler32

implementuje ten interfejs.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 34

Klasa główna programu

CheckedIODemo

:

import java.io.*;
public class CheckedIODemo {
public static void main(String[] args) throws IOException {
Adler32 inChecker = new Adler32();
Adler32 outChecker = new Adler32();
CheckedInputStream in = null;
CheckedOutputStream out = null;
try { in = new CheckedInputStream(

new FileInputStream("plikWE.txt"), inChecker);

out = new CheckedOutputStream(

new FileOutputStream("plikWY.txt"), outChecker);

} catch (FileNotFoundException e) {
System.err.println("CheckedIODemo: " + e);
System.exit(-1);
} catch (IOException e) {
System.err.println("CheckedIODemo: " + e);
System.exit(-1);

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 35

}
int c;
while ((c = in.read()) != -1)

out.write(c);

System.out.println("Suma kontrolna WE: " + inChecker.getValue());
System.out.println("Suma kontrolna WY: "+ outChecker.getValue());
in.close();
out.close();
}
}

W metodzie

main

utworzono dwa obiekty klasy

Adler32

dla obliczania

sumy kontrolnej dwóch obiektów klas

CheckedOutputStream

i

CheckedInputStream

, które otwarte zostaj

ą

dla dwóch plików. Pierwszy

obiekt wczytuje dane z 1-szego pliku a drugi zapisuje je w drugim pliku -
oba wykorzystuj

ą

przy tym swoje obiekty klasy

Adler32

w celu

modyfikacji sumy kontrolnej.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 36

5.3

Serializacja

obiektu

(klasy

ObjectInputStream,

ObjectOutputStream

)

Klasy bajtowych strumieni

ObjectInputStream

i

ObjectOutputStream

umo

ż

liwiaj

ą

zapis i odczyt trwałego obiektu, w tym serializacj

ę

i

deserializacj

ę

obiektu.

Zastosowanie serializacji

:



Dla

"Remote Method Invocation"

(RMI) - komunikacja obiektów poprzez

gniazdka - przekazywanie obiektu pomi

ę

dzy klientem i serwerem.



Trwało

ść

obiektu w aplikacji - archiwizacja obiektu umo

ż

liwi jego

odtworzenie po ponownym wywołaniu programu.


Klasa obiektu podlegaj

ą

cego serializacji musi implementowa

ć

interfejs

Serializable

.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 37

1) Mechanizmy serializacji obiektów

Zapis obiektu do strumienia (

ObjectOutputStream)

Np.

FileOutputStream out = new FileOutputStream("Czas.txt");
ObjectOutputStream s = new ObjectOutputStream(out);

//Nasz obiekt

s.writeObject("Dzisiaj");

// Serializacja napisu

s.writeObject( new Date());

// Serializacja obiektu klasy

s.flush();

Obiekt klasy

ObjectOutputStream

tworzony jest na obiekcie innej klasy

strumieniowej, np.

FileOutputStream

(dla pliku "Czas.txt" w powy

ż

szym

przykładzie). Metoda

writeObject

zapisuje do pliku zarówno napis jak i

obiekt klasy

Date

.

ObjectOutputStream

implementuje interfejs

DataOutput

- s

ą

tu metody

dla zapisu elementarnych typów danych:

writeInt, writeFloat, writeUTF

.

Metoda

writeObject

zgłasza wyj

ą

tek

NotSerializableException

je

ś

li nie

mo

ż

e dokona

ć

serializacji przekazanego jej obiektu.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 38

Odczyt obiektu ze strumienia (

ObjectInputStream)

Np.

FileInputStream in = new FileInputStream("Czas");
ObjectInputStream s = new ObjectInputStream(in);

// Nasz obiekt

String today = (String)s.readObject();

// Deserializuj napis

Date date = (Date)s.readObject();

// Deserializauj obiekt

Obiekt klasy

ObjectInputStream

konstruowany jest na obiekcie innej

klasie strumieniowej - w podanym przypadku jest ni

ą

FileInputStream

.

Metoda

readObject

pozwala na wczytanie obiektu, np. typu

String

i

Date

z

pliku.

Zwraca

ona

referencj

ę

typu

Object

,

która

musi

by

ć

przekonwertowana na wła

ś

ciwy typ referencji.

ObjectInputStream

implementuje interfejs

DataInput

wyznaczaj

ą

cy

metody dla odczytu elementarnych typów danych, jak np.

readInt,

readFloat, readUTF

.

Deserializacj

ę

obiektu zapewnia metoda

defaultReadObject

w klasie

ObjectInputStream

.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 39

2) Zapewnienie standardowej serializacji obiektu w naszej klasie

Obiekt mo

ż

e zosta

ć

serializowany tylko wtedy, gdy jego klasa

implementuje interfejs

Serializable

(ale jest to PUSTY interfejs):

package java.io;
public interface Serializable {

// Jest to pusty interfejs przeznaczony dla

// zaznaczania klas, dla których zdefiniowano serializacj

ę

.

};

Wykorzystanie - deklarowanie implementowania interfejsu:

public class MojaSerializowalnaKlasa implements Serializable {
...
}

ale bez konieczno

ś

ci implementacji jakie

ś

metody.

Zadanie

serializacji

obiektów

takiej

klasy

przejmie

metoda

defaultWriteObject

w klasie

ObjectOutputStream

. Wypisuje ona

automatycznie nast

ę

puj

ą

ce dane potrzebne do odtworzenia obiektu:

klas

ę

obiektu, sygnatur

ę

klasy, warto

ś

ci wszystkich nie przechodnich i

niestatycznych pól, w tym warto

ś

ci referencji do innych obiektów.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 40

3) Indywidualny sposób serializacji obiektu

Własna obsługa serializacji i deserializacji obiektu jest mo

ż

liwa po

zdefiniowaniu metod

writeObject

i

readObject

. Ich rola polega na

przekazaniu dodatkowej informacji o obiekcie do lub ze strumienia.

Metoda

writeObject

musi woła

ć

domy

ś

ln

ą

metod

ę

serializacji

defaultWriteObject

danego strumienia swoj

ą

pierwsz

ą

instrukcj

ą

:

private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();

// Własny kod serializacji ...

}

Metoda

readObject

powinna wczytywa

ć

wszystko to co zapisano

metod

ą

writeObject

. Jej struktura:

private void readObject(ObjectInputStream s) throws IOException {
s.defaultReadObject();

// Własna deserializacja obiektu ...

...

// Ewentualnie wykorzystanie informacji dla modyfikacji obiektu

...

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 41

}

Implementacja interfejsu

Externalizable

Aby uzyska

ć

wył

ą

czn

ą

odpowiedzialno

ść

naszej klasy za serializacj

ę

jej

obiektów nale

ż

y zaimplementowa

ć

interfejs

Externalizable

.

Dla obiektów typu

Externalizable

automatycznie zapisywana jest jedynie

identyfikacja klasy

. Klasa odpowiada za zapis i odczyt zawarto

ś

ci jej obiektu i

za koordynacj

ę

w tej sprawie ze swoj

ą

klas

ą

bazow

ą

.

package java.io;
public interface Externalizable extends Serializable {
public void writeExternal(ObjectOutput out) throws IOException;
public void readExternal(ObjectInput in) throws IOException,
java.lang.ClassNotFoundException;
}

Klasa typu

Externalizable

musi zaimplementowa

ć

metody publiczne

writeExternal

i

readExternal

.

Wi

ąż

e si

ę

to z ryzykiem uzyskania bezpo

ś

redniego dost

ę

pu przez program

klienta do zasobów obiektu tej klasy. Dlatego mo

ż

na tak post

ą

pi

ć

jedynie z

klasami nie zawieraj

ą

cymi informacji zabezpieczonej lub krytycznej dla

zachowania si

ę

programu.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 42

Ochrona wra

ż

liwej informacji


1) Pola zawieraj

ą

ce

wra

ż

liwe

dla systemu dane oznaczane s

ą

jako

private transient

.

Pola typu

transient

i

static

nie podlegaj

ą

serializacji / deserializacji.

2)

Cało

ś

ciowo "wra

ż

liwe" klasy

w ogóle nie powinny by

ć

serializowane

- nie nale

ż

y implementowa

ć

Serializable

lub

Externalizable

.

3) Mo

ż

na w metodach

writeObject

i

readObject

weryfikowa

ć

poprawno

ść

stanu obiektu

i w razie bł

ę

dnego stanu

zgłosi

ć

wyj

ą

tek

NotSerializableException

, co uchroni program przed korzystaniem z

obiektu.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 43

5.4 Współpraca z plikami o dost

ę

pie swobodnym

Strumienie znakowe i bajtowe posiadaj

ą

sekwencyjny dost

ę

p.

Inaczej jest z klas

ą

RandomAccessFile

, która umo

ż

liwia swobodny dost

ę

p

do elementów pliku.

Mo

ż

liwe jest te

ż

zdefiniowanie nad tym strumieniem strumieni

filtruj

ą

cych, tzn. implementuj

ą

cych interfejsy

DataInput

i

DataOutput

.

Np.

ZIP jest to format archiwizacji plików. Dost

ę

p sekwencyjny do takiego

pliku wymaga przeczytania du

ż

ej cz

ęś

ci pliku zanim dotrzemy do

katalogu zawieraj

ą

cego informacj

ę

o interesuj

ą

cych nas plikach.

W przypadku

swobodnego dost

ę

pu

wykorzystamy metod

ę

seek

w celu

przeszukania pliku (bez konieczno

ś

ci odczytu) i dotarcia do katalogu.

Utworzenie obiektu

tej klasy

RandomAccessFile

wymaga przekazania

nazwy pliku lub obiektu klasy

File

oraz sposobu współpracy z plikiem.

Np.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 44

new RandomAccessFile("plikWE.txt", "r");

// Otwarcie dla odczytu

new RandomAccessFile("plikWEWY.txt", "rw");

// Odczyt i zapis


Klasa

RandomAccessFile

słu

ż

y zarówno do odczytu jak i zapisu do pliku.

Nie dziedziczy

ona z

InputStream

ani z

OutputStream

.

Jednak

implementuje

interfejsy

DataInput

i

DataOutput

co umo

ż

liwia

zastosowanie do niej strumieni filtruj

ą

cych.

Operowanie na pliku odbywa si

ę

za pomoc

ą

metod wyznaczonych przez

interfejsy

DataInput

i

DataOutput

.

Wska

ź

nik pliku

- wskazuje aktualn

ą

pozycj

ę

w pliku, od 0 do liczby

bajtów. Wska

ź

nik przesuwany jest odpowiednio do liczby bajtów dla

operacji odczytu lub zapisu.
S

ą

te

ż

metody jawnej modyfikacji wska

ź

nika pliku:



int skipBytes(int)

- przesu

ń

wska

ź

nik wprzód o okre

ś

lon

ą

liczb

ę

bajtów.



void seek(long)

- umie

ść

wska

ź

nik bezpo

ś

rednio przez zadanym bajtem.



long getFilePointer()

- zwró

ć

poło

ż

enie wska

ź

nika wyra

ż

one w bajtach.

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 45

Tworzenie strumieni filtruj

ą

cych dla plików o swobodnym dost

ę

pie

Przykład.

Powrócimy do przykładu z

CheckedIODemo

.

Jednak teraz

utworzymy strumienie filtruj

ą

ce dla klasy

RandomAccessFile

.

(1) Teraz klasa

CheckedDataOutput

jest modyfikacj

ą

poprzedniej klasy

CheckedOutputStream

- oblicza sum

ę

kontroln

ą

danych zapisywanych do

strumienia. Jednak operuje na obiektach implementuj

ą

cych

DataOutput

a

nie na obiektach klasy

OutputStream

.

(2) Klasa

CheckedDataInput

jest modyfikacj

ą

klasy

CheckedInputStream

,

pracuj

ą

c

ą

na obiektach

DataInput

zamiast

InputStream

.

(3) Ró

ż

nice mi

ę

dzy

CheckedDataOutpu

t

a

CheckedOutputStream:

(I)

CheckedDataOutput

nie dziedziczy po

FilterOutputStream

a implementuje

interfejs

DataOutput

:

public class CheckedDataOutput implements DataOutput { ...

(II) W

CheckedDataOutput

zadeklarowano prywatne pole - obiekt typu

DataOutput

,

do którego zapisywane b

ę

d

ą

dane.

private DataOutput out;

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 46

(III) Konstruktor klasy

CheckedDataOutput

tworzy obiekt "osadzony" na

obiekcie

DataOutput

a nie na

OutputStream

.

public CheckedDataOutput(DataOutput out, Checksum cksum) {
this.cksum = cksum;
this.out = out;
}

(IV) Konstruktor nie woła

super(out)

jak w

CheckedOutputStream

,

gdy

ż

klasa dziedziczy z klasy

Object

a nie klasy strumieniowej.

(4) Podobnych zmian dokonano w

CheckedDataInput

:

(I)

CheckedDataInput

implementuje

DataInput

.

(II) W

CheckedDataInput

zadeklarowano prywatne pole typu

DataInput

na którym osadzono obiekt tej klasy.
(III) Konstruktor w

CheckedDataInput

wymaga obiektu

DataInput

.

(5) Równie

ż

metody

readXxxx

w klasie

CheckedDataInput

posiadaj

ą

zmienione nazwy i sygnatury:

public byte readByte() throws IOException {

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 47

byte b = in.readByte();
cksum.update(b);
return b;
}
public void readFully(byte[] b) throws IOException {
in.readFully(b, 0, b.length);
cksum.update(b, 0, b.length);
}
public void readFully(byte[] b, int off, int len) throws IOException {
in.readFully(b, off, len);
cksum.update(b, off, len);
}

(6) Mamy teraz dwa programy testuj

ą

ce:



poprzedni

CheckedDIODemo

, sprawdzał działanie filtrów na plikach o

sekwencyjnym dost

ę

pie (

DataInputStream

i

DataOutputStream

).



nowy

CheckedRAFDemo

, sprawdza filtry dla plików o swobodnym

dost

ę

pie (

RandomAccessFile

)

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 48

Jedyna ró

ż

nica mi

ę

dzy nimi polega na typie otwieranych obiektów.

W

CheckedDIODemo

:

in = new

CheckedDataInput

(new DataInputStream(

new FileInputStream("plikWE.txt")), inChecker);
out = new

CheckedDataOutput

(new DataOutputStream(

new FileOutputStream("plikWY.txt")), outChecker);

W

CheckedRAFDemo

:

in = new

CheckedDataInput

(

new RandomAccessFile("plikWE.txt", "r"), inChecker);
out = new

CheckedDataOutput

(

new RandomAccessFile("plikWY.txt", "rw"), outChecker);

background image

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 49

5.5 Pozostałe klasy w java.io

Poza omawianymi klasami

w pakiecie

java.io

wyst

ę

puj

ą

klasy i interfejsy:

File

Reprezentuje plik nale

żą

cy do rodzimego systemu plików. Mo

ż

na

utworzy

ć

obiekt klasy

File

dla pliku.

FileDescriptor

Reprezentuje uchwyt (lub deskryptor) do otwartego pliku lub gniazdka.
Ta klasa zwykle nie jest u

ż

ywana przez programist

ę

u

ż

ytkowego.

StreamTokenizer

Rozdziela strumie

ń

na "token-y" - elementarne jednostki dla parsera

tekstu (słowo, symbol) .

FilenameFilter

Korzysta z niej metoda

list

w klasie

File

dla okre

ś

lenia, które pliki w

kartotece maj

ą

by

ć

wybrane.

5. Strumienie wej

ś

cia - wyj

ś

cia

W. Kasprzak: Programowanie zdarzeniowe

5 - 50

Strumienie WE-WY w pakiecie

java.util.zip

CheckedInputStream , CheckedOutputStream

Para

strumieni

realizuj

ą

ca

sprawdzanie

sumy

kontrolnej

dla

wczytywanych lub wysyłanych danych.

DeflaterOutputStream, InflaterInputStream

Para strumieni do kompresji i dekompresji danych.

GZIPInputStream, GZIPOutputStream

Dla odczytu i zapisu komprymowanych danych w formacie GZIP.

ZipInputStream, ZipOutputStream

Dla odczytu i zapisu komprymowanych danych w formacie ZIP.


Wyszukiwarka

Podobne podstrony:
Proz S2 id 402992 Nieznany
Proz S12 id 402989 Nieznany
Proz S9 id 402999 Nieznany
Proz S8 id 402998 Nieznany
Proz S13 id 402990 Nieznany
Proz S4 id 402994 Nieznany
Proz S3 id 402993 Nieznany
Proz S14 id 402991 Nieznany
Proz S7 id 402997 Nieznany
Proz S10 id 402987 Nieznany
Proz S2 id 402992 Nieznany
Proz S12 id 402989 Nieznany
chemia proz maj 2011 cke id 112 Nieznany
Abolicja podatkowa id 50334 Nieznany (2)
4 LIDER MENEDZER id 37733 Nieznany (2)
katechezy MB id 233498 Nieznany
metro sciaga id 296943 Nieznany
perf id 354744 Nieznany
interbase id 92028 Nieznany

więcej podobnych podstron