piasecki,podstawy programowania, Wejście wyjście w javie

Wejście/wyjście w Javie.


Problemy :


System wejścia/wyjścia jest oparty na pojęciu strumienia (znakowego lub binarnego ) .

Realizowany przez hierarchię klas - na pierwszy rzut oka bardzo rozbudowaną, ale i tak w miarę prosty w wyniku wykorzystania jednego z rodzajów wzorców projektowych - dekoratorów.

Na szczęście większość z nich jest przeznaczona do bardziej złożonych działań - wykorzystanie systemu do wykonywania podstawowych zadań ( drukowanie wyników , wczytywanie danych, współpraca z plikami ) jest stosunkowo proste.


Podstawowe klasy hierarchii to : InputStraem ( wejście binarne), OutputStream ( wyjście binarne), Reader(wejście znakowe) i Writer (wyjście znakowe). Podstwowe metody to : read - dla wejścia i write - dla wyjścia.


Dla ułatwienia podzieliłem wykład na dwie części :

Zgodnie z przyjętym założeniem przekazuję tylko podstawowe informacje umożliwiające efektywne wykorzystanie strumieni ( większość z tych działań można zrealizować na wiele sposobów - zazwyczaj będę ograniczał się do jednego).



  1. Standardowe strumienie znakowe


    1. Drukowanie wyników

Przy prostych wydrukach wystarczy wykorzystanie standardowego strumienia out ( obiekt klasy PrintStream) z klasy System z podstawowymi metodami : print, println i printf ( wydruk z formatowaniem). Jeśli zależy nam na efektywności i przenośności lepiej jest definiować własny strumień klasy PrintWriter , np. :

PrintWriter wyj= new PrintWriter( new BufferedWriter(new OutputStreamWriter (System.out)),true);

Do bardziej złożonych wydruków ( np. tabele, wykazy) należy stosować metodę printf.


PrintWriter

printf (String format, Object... args)


Parametr format zawiera bezpośredni tekst i opis sposobu drukowania argumentów.


Ogólna postać formatu dla pojedynczego argumentu :


%[argument_index$][flags][width][.precision]conversion


Elementy w nawiasach [] są opcjonalne.

argument_index numer argumentu ( od 1) , jeśli jest opuszczony drukuje kolejny (liczone są tylko nieindeksowane) element, indeks < oznacza poprzedni argument ( umożliwia wielokrotny wydruk jednego argumentu)

flags ciąg znaków modyfikujących sposób wydruku ( znaczenie zależy od typu drukowanego elementu)

width minimalna szerokość pola wydruku

precision górne ograniczenie szerokości pola wydruku ( znaczenie zależy od typu drukowanego elementu)

conversion sposób formatowania elementu ( zbiór poprawnych konwersji zależy od typu elementu)

Formaty dla róznych typów argumentów :

- boolean

%[argument_index$][flags][width][.precision]conversion


konwersja : b lub B (wydruk wielkimi literami)

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

precyzja - maksymalna szerokość pola (brak oznacza brak ograniczeń)

flaga - '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)


- char

%[argument_index$][flags][width]conversion


konwersja : c lub C (wydruk wielkimi literami)

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

flaga - '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)

Uwagi : aby wydrukować znak procentu podajemy %% - format bezargumentowy

%n - oznacza niezależny od platformy znak nowej linii - bezargumentowy


- typy całkowite ( byte, short,int,long)

%[argument_index$][flags][width]conversion


konwersja : d

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

flagi: '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)

'0' uzupełnianie pola 0 a nie spacją

'+' znak jest zawsze drukowany

' ' dla liczb dodatnich zamiast znaku drukowana spacja

'(' liczby ujemne są drukowane w ( ) ale bez znaku -


- typy rzeczywiste (float, double)

%[argument_index$][flags][width][.precision]conversion


konwersja : e lub E postać naukowa (wykładnicza)

f postać stałoprzecinkowa

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

precyzja - liczba miejsc po kropce dziesiętnej uzupełniana 0 lub obcinana przez zaokrąglenie ( domyślnie 6)

flaga - '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)

'#' wymusza druk kropki dziesiętnej nawet jeśli część ulamkowa jest 0

- napisy (również obiekty ze zdefiniowaną metodą toString)

%[argument_index$][flags][width][.precision]conversion


konwersja : s lub S (wydruk wielkimi literami)

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

precyzja - maksymalna szerokość pola (brak oznacza brak ograniczeń)

flaga - '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)


- data/czas (klasy Calendar i Date)


%[argument_index$][flags][width][.precision]conversion


konwersja : t lub T (pierwszy znak , konwersja jest zawsze dwuznakowa)

po szczegółowy opis znaczenia drugiego znaku odsyłam do helpa

szerokość - minimalna szerokość pola ( uzupełniana spacjami)

precyzja - maksymalna szerokość pola (brak oznacza brak ograniczeń)

flaga - '-' wyrównanie do lewego brzegu pola ( domyślne wyrównanie do prawego)


Uwagi :

- jeżeli wydruk nie kończy się znakiem nowej linii należy użyć metody flush( ) do natychmiastowego wypisania na ekranie

- podobne metody ma metoda String.format(...) szczególnie przydatna do przeciążania metody toString dla obiektów ( ale nie tylko )


    1. Wczytywanie danych

W wielu wypadkach do wczytywania danych wystarczą proste klasy ( InputStream lub Reader ) jednak wygodniejsze ( i szybsze ) jest użycie buforowanego wejścia ( BufferedReader), a najbardziej elastyczne jest wykorzystanie klasy dzielącej zawartość strumienia na proste elementy tzw. tokeny ( StreamTokenizer ).


Deklaracja zmiennych :

BufferedReader wej= new BufferedReader( new InputStreamReader(System.in));

StreamTokenizer st = new StreamTokenizer(wej); // argument typu Reader


Uwaga : praktycznie wszystkie metody wejściowe zgłaszają wyjątek IOException, który należy obsłużyć lub przekazać do metody wywołującej.


Podstawowe metody klasy BufferedReader :


public int read()throws IOException

wczytanie pojedynczego znaku ( -1 gdy koniec strumienia)


public int read(char[] cbuf,int off,int len)throws IOException

wczytanie ciągu znaków do fragmentu ( można opuścić off i len) tablicy znakowej ( wynik - liczba wczytanych znaków lub -1 - próba czytania na końcu strumienia )


public String readLine()throws IOException

wynikiem jest zawartość wczytanej linii tekstu


public long skip(long n) throws IOException

pomiń n znaków


public boolean ready()throws IOException

true jeśli w strumieniu są jakieś znaki


public int available()throws IOException

liczba znaków oczekujących w strumieniu ( jest to metoda klasy InputStream dostępna dzięki użyciu strumienia System.in)



Aby wczytać wartość liczbową używamy metody readln, a następnie odpowiedniej metody parse ( Boolean, Int , Double ...). Niestety metody te są wrażliwe ( zgłaszają NumberFormatException) na niepotrzebne znaki ( nawet spacje) więc trzeba je samemu usuwać . Tej wady nie ma StreamTokenizer.


Uwaga: warto przeanalizować możliwości klasy Scanner.


Klasa ta może rozpoznawać : nazwy(słowa), liczby, stringi i komentarze. Typowy sposób wykorzystania to :


void

commentChar(int ch)

definiuje znak będący początkiem komentarza wierszowego

 void

eolIsSignificant(boolean flag)

Określa czy nowa linia jest traktowana jako token

 void

lowerCaseMode(boolean fl)

wymusza zmianę znaków słowa na małe litery

 void

ordinaryChar(int ch)
          wymusza traktowanie znaku jako "zwykłego"

 void

ordinaryChars(int low, int hi)
           znaki z zakresu
low <= c <= high mają być traktowane jako

 void

quoteChar(int ch)
          ustal znak oznaczający napis - domyślny ( " )

 void

resetSyntax()
           traktuj wszystkie znaki jako zwykłe

 void

slashSlashComments(boolean flag)
          rozpoznawanie komentarzy w stylu C++ ( // )

 void

slashStarComments(boolean flag)
          rozpoznawanie komentarzy w stylu C ( /* )

 void

whitespaceChars(int low, int hi)
          traktuj znaki z zakresu low <= c <= high jako białe spacje

 void

wordChars(int low, int hi)
          traktuj znaki z zakresu low <= c <= high jako składowe słowa





wej.nextToken( )

wynikiem jest typ tokena ( można go również odczytać z pola wej.ttype )

TT_EOF - koniec strumienia

TT_EOL - koniec linii ( tylko gdy ustawiony jest .....)

TT_NUMBER - wartość liczbowa, umieszczona w polu val (typu double)

TT_WORD - nazwa(napis) , umieszczony w polu sval ( typu String).


Dodatkowe metody :


 int

lineno()
zwraca bieżący numer linii          

 void

pushBack()
          zwraca ostatnio odczytany token do strumienia



Uwaga: nie trzeba zamykać strumieni zbudowanych na bazie strumieni standardowych ( out, in, err).


W przypadku prowadzenia analizy danych zapisanych w strumieniu przez wiele różnych metod bardzo przydatna jest możliwość zwrotu (lub wręcz wstawienia ) do strumienia ostatnio odczytanego znaku( lub ciągu znaków). Taką możliwość daje metoda unread( ..) klasy PushBackReader.


Przykład :


import java.util.*;

import java.io.*;


public class ComparatorPublikacji implements Comparator<Publikacja>,Serializable

{ public int compare(Publikacja p1,Publikacja p2)

{ return p1.autor.compareTo(p2.autor)!=0 ? p1.autor.compareTo(p2.autor) : p1.tytul.compareTo(p2.tytul);}

}


// interfejs utworzony tylko po to, żeby przekazywać strumieni jako parametry metod

import java.io.*;


public interface Strumien

{ PrintWriter wyj= new PrintWriter( new BufferedWriter(new OutputStreamWriter(System.out)),true);

BufferedReader wej= new BufferedReader( new InputStreamReader(System.in));

StreamTokenizer st = new StreamTokenizer(wej); // argument typu Reader

}


import java.io.*;


public abstract class Publikacja implements Comparable, Cloneable, Serializable, Strumien

{ String tytul;

String autor;

int rok;


Publikacja()

{ wyj.print(" Podaj Tytul Autora i Rok "); wyj.flush();

try {st.nextToken();

tytul=st.sval;

st.nextToken();

autor=st.sval;

while(st.nextToken()!=st.TT_NUMBER);

rok=(int)st.nval;

}catch(IOException e) {System.out.println("Publikacja Blad wczytywania");}

}


public Publikacja clone()

{ try{ Publikacja p=(Publikacja)super.clone();

p.tytul= new String(tytul);

p.autor=new String(autor);

return p;

} catch(CloneNotSupportedException e){return null;}

}

public String toString()

{ return String.format("%-30s %-15s %6d ", tytul,autor,rok); }

public boolean equals(Publikacja p)

{ return p!=null && tytul.equals(p.tytul) && autor.equals(p.autor) ; }

public int hashCode()

{ return tytul.hashCode() & autor.hashCode(); }

public int compareTo(Object p1)

{ Publikacja p=(Publikacja)p1;

return (tytul.compareTo(p.tytul)!=0 ? tytul.compareTo(p.tytul) : autor.compareTo(p.autor));

}

}


import java.io.*;


public class Ksiazka extends Publikacja

{ String wydawnictwo;


public Ksiazka()

{ super();

try{ wyj.print(" Podaj wydawnictwo ");wyj.flush();

st.nextToken();

wydawnictwo=st.sval;

} catch(IOException e){ System.out.println(" Ksiazka Blad wejscia ");}

}


public String toString()

{ return super.toString() + String.format(" Ksiazka wydana przez %s ",wydawnictwo);}

}



import java.io.*;

public class Artykol extends Publikacja

{ String czasopismo;


public Artykol()

{super();

wyj.print(" w czasopismie ");wyj.flush();

try{ st.nextToken();

czasopismo=st.sval;

}catch(IOException e) { System.out.println(" Artykol Blad wejscia ");}

}


public String toString()

{ return super.toString() + String.format(" Artykol w : %s",czasopismo);}

}


import java.util.*;

import java.io.*;


public class test implements Strumien

{

SortedSet<Publikacja> s = new TreeSet<Publikacja>();

public void druk(Collection<Publikacja> s)

{ for(Publikacja el:s)

wyj.printf("%s %n" ,el);

wyj.println();

}

public void nowaPublikacja()

{ String odp="";

while(!(odp.equals("Ksiazka")||odp.equals("Artykol")))

{ wyj.println(" Ksiazka czy Artykol ");

try{ st.nextToken();

odp=st.sval;

} catch(IOException e) { System.out.println(" nowa Publikacja Blad wejscia ");return;}

}

s.add(odp.equals("Ksiazka")? new Ksiazka() : new Artykol());

}

public void druk1(Iterator<Publikacja> it)

{ while(it.hasNext())

System.out.println(it.next()+" , ");

System.out.println();

}

public void test()

{ char odp = ' ';

do { wyj.println(" Co chcesz robic : Dodaj publikacje, Wypisz liste, Koniec ");

try { st.nextToken(); }

catch(IOException e){ System.out.println(" Blad menu "); return;}

odp=st.sval.toLowerCase().charAt(0);

switch(odp)

{case 'd' : nowaPublikacja();break;

case 'w' : druk(s); break;

case 'k' : break;

default : wyj.printf(" Nie ma takiej opcji %n");

}

} while (odp!='k');

}

}



  1. Strumienie plikowe


Do czego wykorzystujemy pliki :

    1. przygotowywanie dużych zestawów danych wejściowych

    2. do zapisu obszernych wyników

    3. do przechowywania zgromadzonych danych między kolejnymi uruchomieniami aplikacji

    4. do pracy z wielkimi ( nie mieszczącymi się w pamięci operacyjnej ) zbiorami danych.


1 i 2 - pliki tekstowe

3 i 4 - pliki binarne ( do 4 najlepsze są pliki o dostępie bezpośrednim).


Uwaga : strumienie plikowe trzeba po wykorzystaniu zamykać używając metody close( ).


Przy wykorzystaniu plików tekstowych mamy dwa rozwiązania :


Przez wywołanie metody z klasy System :


static void

setErr(PrintStream err)

static void

setIn(InputStream in)

static void

setOut(PrintStream out)


System.setIn("dane.txt");

System.setOut("wyniki.txt");

PrintWriter wyj= new PrintWriter( new BufferedWriter(new OutputStreamWriter(System.out)),true);

BufferedReader wej= new BufferedReader( new InputStreamReader(System.in));

StreamTokenizer st = new StreamTokenizer(wej);



Konstruktory ( analogiczne dla FileWriter):

public FileReader(String fileName) throws FileNotFoundException

public FileReader(File file) throws FileNotFoundException

public FileWriter(String fileName) throws FileNotFoundException

public FileWriter(File file) throws FileNotFoundException

public FileWriter(String fileName, boolean append) throws FileNotFoundException

public FileWriter(File file, boolean append) throws FileNotFoundException


np:

PrintWriter wyj= new PrintWriter( new BufferedWriter(new FileWriter("wyniki.txt")),true);

lub prościej

PrintWriter wyj= new PrintWriter("wyniki.txt");


BufferedReader wej= new BufferedReader( new FileReader("dane.txt"));

StreamTokenizer st = new StreamTokenizer(wej);


Wykorzystanie tak jak to opisano w poprzednim wykładzie.


Przy plikach binarnych wykorzystujemy klasy : FileInputStream i FileOutputStream ( dla prostych danych ) lub ObjectInputStream i ObjectOutputStream ( dla obiektów).


Konstruktory ( analogiczne dla FileOutputStream + opcjonalny parametr append):

public FileInputStream(String fileName) throws FileNotFoundException

public FileInputStream(File file) throws FileNotFoundException


Np.

FileInputString wej = new FileInputString("baza.dta");

FileOutputString wyj = new FileOutputString("baza.dta");


Podstawowe metody raead/write są przeciążone dla wszystkich typów prostych i ciągów bajtów.

Do pracy z obiektami powinniśmy korzystać z klas ObjectInputStream i ObjectOutputStream.


np.

ObjectInputStream wejOb= new(ObjectInputStream(wej));

ObjectOutputStream wyjOb= new(ObjectOutputStream(wyj));


Dodatkowe metody to :

public final Object readObject( ) throws IOException,ClassNotFoundException

public final void writeObject(Object obj) throws IOException


Uwaga: jeśli obiekt ma pola typu obiektowego należy wykorzystać mechanizm serializacji\deserializacji. Każda z klas występujących w grafie zapisywanych obiektów musi implementować interfejs Serializable. Po zapisie i odczycie mamy odtworzony cały graf obiektów ( identyczne obiekty składowe nie są powielane).


Przy pracy bezpośrednio z plikiem ( plik jako wielka tablica w pamięci zewnętrznej ) wykorzystujemy klasę RandomAccesFile ( nie jest to podejście strumieniowe).


Konstruktory:

public RandomAccessFile(String name,String mode)throws FileNotFoundException

public RandomAccessFile(File file,String mode)throws FileNotFoundException


Tryby dostępu to :

r - tylko odczyt

rw - odczyt i zapis

rws, rwd - fizyczny zapis zmian po każdej modyfikacji


Podstawowe metody to przciążone read/write i close.


Dodatkowe metody udostępniane przez klasę :

long getFilePointer( ) - daj bieżącą pozycję kursora pliku

long length( ) - długość (wielkość) pliku

void seek ( long pos) - ustaw kursor na pozycję

void setLength(long newLength) - zmień wielkość pliku

void skipBytes(int n ) - przesuń kursor o n bajtów




Jeśli potrzebujemy odczytać informacje o pliku , manipulować plikami lub kartotekami powinniśmy wykorzystać klasę File.


Podstawowy konstruktor : File( String nazwa)

Wybrane ( proste metody) :


 boolean

canRead() można czytać z pliku.

 boolean

canWrite() można zapisywać do pliku.

 boolean

createNewFile() utwórz nowy ( pusty ) plik.

static File

createTempFile(String prefix, String suffix)
          Utwórz plik tymczasowy.

 boolean

delete() Skasuj plik.

 boolean

isDirectory() Czy to kartoteka.

 boolean

isFile() czy to plik.

 long

length() wielkość pliku.

boolean


renameTo(File dest) zmień nazwę pliku.

 


Przykład wykorzystania plików ( pomijam klasy, które nie uległy zmianie ).


import java.util.*;

import java.io.*;


public class test implements Strumien

{

public void test() throws IOException,ClassNotFoundException

{ PrintWriter plikWyj= new PrintWriter("wyniki.txt");

Spis spis=new Spis();

spis.wczytaj();

char odp = ' ';

do { wyj.println(" Co chcesz robic : Dodaj publikacje, Wypisz liste, Save, Restore, Koniec ");

st.nextToken(); }

odp=st.sval.toLowerCase().charAt(0);

switch(odp)

{case 'd' : spis.nowaPublikacja(st,true);break;

case 'w' : plikWyj.printf("%s %n",spis); break;

case 's' : spis.save(); break;

case 'r' : spis=spis.restore(); break;

case 'k' : break;

default : wyj.printf(" Nie ma takiej opcji %n");

}

} while (odp!='k');

if(plikWyj != null) plikWyj.close();

}

}



import java.util.*;

import java.io.*;


public class Spis implements Strumien,Serializable

{ SortedSet<Publikacja> s = new TreeSet<Publikacja>();

public String toString()

{ String wynik=new String();

for(Publikacja el:s)

wynik=wynik+String.format("%s %n" ,el);

return wynik;

}

public void nowaPublikacja(StreamTokenizer st,boolean standard)throws IOException

{ String odp="";

while(!(odp.equals("Ksiazka")||odp.equals("Artykol")))

{ if(standard) {wyj.println(" Ksiazka czy Artykol ");}

st.nextToken();

odp=st.sval;

}

s.add(odp.equals("Ksiazka")? new Ksiazka(st,standard) : new Artykol(st,standard));

}

public void save()throws IOException

{ ObjectOutputStream plik = new ObjectOutputStream(new BufferedOutputStream( new FileOutputStream("baza.dta")));

plik.writeObject(this);

plik.close();

}

public Spis restore()throws IOException, ClassNotFoundException

{ ObjectInputStream plik = new ObjectInputStream(new BufferedInputStream( new FileInputStream("baza.dta")));

Spis tmp=(Spis)plik.readObject();

plik.close();

return tmp;

}

public void wczytaj() throws IOException

{ StreamTokenizer plikWej=new StreamTokenizer(new FileReader("dane.txt"));

while(plikWej.nextToken()!=plikWej.TT_EOF)

{plikWej.pushBack();

nowaPublikacja(plikWej,false);

}

}

}


import java.io.*;


public abstract class Publikacja implements Comparable, Cloneable, Serializable, Strumien

{ String tytul;

String autor;

int rok;


Publikacja(StreamTokenizer st,boolean standard)throws IOException

{ if(standard){wyj.print(" Podaj Tytul Autora i Rok "); wyj.flush();}

st.nextToken();

tytul=st.sval;

st.nextToken();

autor=st.sval;

while(st.nextToken()!=st.TT_NUMBER);

rok=(int)st.nval;

}


public Publikacja clone()

{ try{ Publikacja p=(Publikacja)super.clone();

p.tytul= new String(tytul);

p.autor=new String(autor);

return p;

} catch(CloneNotSupportedException e){return null;}

}

public String toString()

{ return String.format("%-30s %-15s %6d ", tytul,autor,rok); }

public boolean equals(Publikacja p)

{ return p!=null && tytul.equals(p.tytul) && autor.equals(p.autor) ; }

public int hashCode()

{ return tytul.hashCode() & autor.hashCode(); }

public int compareTo(Object p1)

{ Publikacja p=(Publikacja)p1;

return (tytul.compareTo(p.tytul)!=0 ? tytul.compareTo(p.tytul) : autor.compareTo(p.autor));

}

}



import java.io.*;


public class Ksiazka extends Publikacja

{ String wydawnictwo;


public Ksiazka(StreamTokenizer st, boolean standard) throws IOException

{ super(st,standard);

if(standard) {wyj.print(" Podaj wydawnictwo ");wyj.flush();}

st.nextToken();

wydawnictwo=st.sval;

}


public String toString()

{ return super.toString() + String.format(" Ksiazka wydana przez %s ",wydawnictwo);}

}



import java.io.*;

public class Artykol extends Publikacja

{ String czasopismo;


public Artykol(StreamTokenizer st, boolean standard) throws IOException

{super(st,standard);

if( standard) {wyj.print(" w czasopismie ");wyj.flush();}

st.nextToken();

czasopismo=st.sval;

}


public String toString()

{ return super.toString() + String.format(" Artykol w : %s",czasopismo);}

}



Wyszukiwarka

Podobne podstrony:
piasecki,podstawy programowania, Typy wyliczeniowe w Javie
piasecki,podstawy programowania, Kolekcje w Javie
piasecki,podstawy programowania, Tablice w Javie
Podstawowe urządzenia wejścia-wyjścia wchodzące w skład zest, wrzut na chomika listopad, Informatyka
piasecki,podstawy programowania, Definicja klasy, tworzenie obiektów
piasecki,podstawy programowania, Podstawowe elementy języka java
piasecki,podstawy programowania, Hierarchia klas, dziedziczenie, polimorfizm
piasecki,podstawy programowania, budowa programu w języku java
piasecki,podstawy programowania, Klasy i metody abstrakcyjne, interfejsy
piasecki,podstawy programowania, Wychwytywanie błędnych zachowań programu
piasecki,podstawy programowania, Instrukcje jezyka Java
Woynarowska Edukacja zdrowotna w nowej podstawie programowej
Nowa podstawa programowa WF (1)
1 Podstawy programowania dialogowego
nowa podstawa programowa sp
11-nkb~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
2-eukl~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2
Zmiany w podstawie programowej w zakresie edukcji matematycznej, Wczesna edukacja, Materiały do prac
1-algo~1, wisisz, wydzial informatyki, studia zaoczne inzynierskie, podstawy programowania, l2

więcej podobnych podstron