Info B VL 7: Input/Output Objektorientiere Programmierung in Java 2003 Ute Schmid (Vorlesung) Elmar Ludwig (Übung) FB Mathematik/Informatik, Universität Osnabrück Info B VL 7: Input/Output – p.174 Exkurs: Design Patterns siehe Cooper, Java Design Patterns Abstrakter Code, Schema, das wiederverwendet werden kann Beispiel: Factory-Pattern X XFactory +XFactory() +do_X() +newObj() : X XY XZ ... +do_X() +do_X() Info B VL 7: Input/Output – p.175 Eingabe-/Ausgabeströme (1) open a stream while more information read information close the stream open a stream while more information write information close the stream Info B VL 7: Input/Output – p.176 Eingabe-/Ausgabeströme (2) Einlesen von Information aus externer Quelle (source): Tastatur, Datei, Speicher, anderes Programm, Internet, ... Ausgabe von Information zu externer Destination (sink): Bildschirm, Datei, Drucker, Speicher, anderes Programm, Internet, ... Information: Zeichen, Objekte, Bilder Verarbeitung immer sequentiell! Info B VL 7: Input/Output – p.177 Struktur von ‘java.io’ (1) Reader Abstrakte Klassen zum Lesen und Schreiben von Character−Strömen Writer InputStream Abstrakte Klassen zum Lesen und Schreiben von Byte−Strömen Object OutputStream RandomAccessFile Lesen und Schreiben an beliebigen Stellen in einer Datei StreamTokenizer Zerlegung von Input in Tokens File Plattform−unabhängige Definition von Datei− und Verzeichnisnamen <<interface>> Serializable <<interface>> Externizable Info B VL 7: Input/Output – p.178 Struktur von ‘java.io’ (2) auf “oberster Ebene”: Abstrakte Klassen zum Lesen/Schreiben von Charund Byte-Strömen: Reader/Writer (Chars), InputStream/OutputStream (Bytes) RandomAccessFile: Lesen und Schreiben von Bytes/Text/primitiven Typen von/in spezifische Position einer Datei StreamTokenizer: Zerlegung des Eingebestroms in Tokenns (einfache lexikalische Analyse) File: BS-unabhängige Repräsentation von Datei- und Pfadnamen. File-Objekt bezeichnet den Dateistrom aus/in den gelesen/geschrieben werden kann. Methoden zum Listem von Verzeichnissen, Pruefen von Rechten etc. Info B VL 7: Input/Output – p.179 File implementiert das Serializable-Interface Character und Byte Ströme Lesen/Schreiben von 16-Bit (unicode) Zeichen: Abstrakte Reader/Writer Klasse und entsprechende Unterklassen (ab Java 1.1). Lesen/Schreiben von 8-Bit Bytes: Abstrakte InputStream/OutputStream Klasse und entsprechende Unterklassen (ab Java 1.0). Ähnliche APIs (Methoden mit gleichem Namen und äquivalenter Signatur) für verschiedene Character- und Byte-Ströme. Für Byte-Ströme werden Byte-Arrays, für Character-Ströme Character-Arrays verarbeitet. Info B VL 7: Input/Output – p.180 ‘read’ und ‘write’ (1) int read() int read(char cbuf[]) int read(char cbuf[], int offset, int length) int write(int c) int write(char cbuf[]) int write(char cbuf[], int offset, int length) read() und write() können IOExceptions werfen. Überladene Methoden: Lesen/Schreiben eines Zeichens/Bytes. Lesen/Schreiben in/aus Array von Zeichen/Bytes. Lesen/Schreiben von length Zeichen/Bytes in/aus Array ab Index offset. Info B VL 7: Input/Output – p.181 ‘read’ und ‘write’ (2) read() liefert int zurück: 255 für Bytes oder 0 65535 (0x00-0xffff) für Characters und 0 -1 für Ende des Stroms. Bei den Methoden, die Arrays verarbeiten, wird die Anzahl der verarbeiteten Zeichen/Bytes zurückgeliefert bzw. -1 für Ede des Stroms. Info B VL 7: Input/Output – p.182 ‘Reader’ und ‘Writer’ (1) InputStreamReader Reader FileReader BufferedReader FileInputStream FilterReader OutputStreamReader Writer BufferedWriter FilterWriter BufferedInputStream InputStream FilterInputStream FileWriter FileOutputStream OutputStream BufferedOutputStream FilterOutputStream Info B VL 7: Input/Output – p.183 ‘Reader’ und ‘Writer’ (2) Um komplexe Funktionalität zu erhalten, werden gerade im I/O-Bereich häufig Objekte komponiert/ineinander verschachtelt. Viele Konstruktoren und Methoden in java.io werfen Exceptions! Die Klasse InputStreamReader bietet eine Reader-Schnittstelle zu einem InputStream (analog für OutputStreamWriter): ein InputStream-Objekt wird in ein InputStreamReader-Objekt eingebettet. public class InputStreamReader extends Reader { public InputStreamReader(java.io.InputStream in); // ... } Info B VL 7: Input/Output – p.184 ‘Reader’ und ‘Writer’ (3) Schreiben in eine Datei und Lesen aus einer Datei kann mit FileWriter und FileReader erledigt werden. Die Angabe von Dateien kann über File-Objekte oder (plattform-spezifische) Dateinamen als Strings erfolgen. Konstruktoren: public class FileReader extends InputStreamReader { // public constructor public FileReader(File file) throws FileNotFoundException; public FileReader(String fileName) throws FileNotFoundException; // ... } Info B VL 7: Input/Output – p.185 ‘Reader’ und ‘Writer’ (4) Puffern von Daten bringt Effizienz: Daten werden (in Array) gesammelt und dann weiterverarbeitet. Die Klasse BufferedReader hat eine readLine()-Methode. Die abstrakten Filter-Klassen FilterReader und FilterWriter erlauben Zusatzfunktionen während des Lesens/Schreibens: z.B. Zählen von Zeichen, Umwandlung von Zeichen etc. Info B VL 7: Input/Output – p.186 Datei Ströme (1) Beispielcode: Copy.java Klasse File: Konstruktor erzeugt File-Objekt aus String. Achtung bei Pfadnamen: Pfadseparatoren sind vom Betriebssystem abhängig Dateiname kann direkt als String an FileReader übergeben werden, z. B. FileReader(farrago.txt"); FileReader ist ein Datei-Strom. FileReader ist Unterklasse von InputStreamReader: Eine Datei ist eigentlich als Folge von Bytes und nicht von Unicode-Zeichen repräsentiert. Die Klasse FileReader realisiert die Anwendung eines InputStreamReader auf ein InputStream-Objekt! Info B VL 7: Input/Output – p.187 Datei Ströme (2) mit new FileReader(...) etc. wird die Datei automatisch geöffnet. Dateien können (sollten) explizit geschlossen werden, damit keine Ausgabe im I/O-Puffer verbleibt (flush). Im Prinzip werden Dateien auch vom Garbage Collector geschlossen, wenn nicht mehr auf sie zugegriffen wird. In dem Programm könnte noch eine Abfrage eingebaut werden, ob der Name der Zieldatei verschieden vom Namen der Quelldatei ist (equals() Methode der Klasse File). Info B VL 7: Input/Output – p.188 Puffern von Daten Beispielcode: BufferDemo.java Beliebige Reader-Objekte können in einen BufferedReader gesteckt werden, also z.B. FileReader-Objekte. (analog für Writer, analog für Byte-Ströme) System.in ist ein InputStream-Objekt! Analog zu BufferedReader in = new BufferedReader(new FileReader(inputFile)); kann natürlich geschrieben werden: FileReader fr = new FileReader(inputFile); BufferedReader in = new BufferedReader(fr); Achtung: bei gepufferten Ausgabe-Strömen muss flush() angewendet werden, damit der Puffer “geleert”, also damit wirklich geschrieben wird. close() führt automatisch ein flushing aus. Info B VL 7: Input/Output – p.189 Filter Ströme (1) Die abstrakten Filter-Klassen von java.io erlauben es, beim Lesen und Schreiben zusätzliche Operationen durchzuführen. Die default-Implementation der Filter-Klassen leiten die Methodenaufrufe an das bei Konstruktion übergebene Objekt weiter, z.B. übliches read(): Null-Filter. Wird eine Unterklasse einer Filter-Klasse wie FilterInputStream definiert, so können genau die Methoden überschrieben werden, von denen man zusätzliche Funktionalität haben möchte. Die Filter-Klassen entsprechen dem Decorator-Pattern. Der Name kommt ursprünglich aus der GUI-Programmierung (z.B. Fenster mit verschiedener Dekoration), ist aber analog für nicht-visuelle Bereiche definiert. Info B VL 7: Input/Output – p.190 Filter Ströme (2) Beispielcode: CaseFilter.java, DecoStream.java Die CaseFilter-Klasse implementiert eine erweiterte Funktionalität für read(): Beim Einlesen werden Kleinbuchstaben in Grossbuchstaben umgewandelt. In der Klasse DecoStream wird nun das read() eines CaseFilter-Objekts verwendet. Direkt beim Einlesen wird der Text nun umformatiert! Vergleiche String und + vs. StringBuffer und append(). Info B VL 7: Input/Output – p.191 Standard IO (1) Auf Betriebssystem-Ebene existieren für jedes laufende Programm drei Ströme: Standard Input, Standard Output und Standard Error. In Java existieren entsprechende Objekte in der System-Klasse: System.in: ist ein InputStream System.out und Systen.err sind bereits in einen PrintStream gepackt (statt OutputStream). Defaultmässig ist Standard Input die Tastatur, Standard Output und Error der Monitor. Die Defaults können über das Betriebssystem, aber auch innerhalb eines Programms (z.B. Java) umdefiniert werden. Info B VL 7: Input/Output – p.192 Standard IO (2) Statische Methoden in der System-Klasse und die Default-Belegung: setIn(InputStream in) setOut(PrintStream out) setErr(PrintStream err) Im Programmbeispiel BufferDemo wurde gezeigt, wie ein System.in-Objekt in ein Reader-Objekt und dann in ein BufferedReader-Objekt gepackt werden kann. Bereits bekannt ist die Verwendung der Methoden System.out.print() und System.out.println(). Beispiecode: Redirecting.java Info B VL 7: Input/Output – p.193 IO Exceptions CharConversionException EOFException java.lang java.io InvalidClassException FileNotFoundException InvalidObjectException Exception IOException InterruptedIOException NotActiveException ObjectStreamException NotSerializableException SyncFailedException OptionalDataException UnsupportedEncodingException StreamCorruptedException UTFDataFormatException WriteAbortedException Info B VL 7: Input/Output – p.194 Random Access RandomAccessFile stammt direkt von Object ab und implementiert die Interfaces DataInput und DataOutput. Die Klasse ermöglicht Lesen und Schreiben sowie das Vorwärts- und Rückwärtsgehen in einer Datei. Sie kann nicht in einen BufferedInputStream o.Ä. gepackt werden. Im Prinzip arbeitet die Klasse wie ein kombinierter DataInputStream und DataOutputStream. Typische Anwendung: Effizientes Lesen aus ZIP-Archiv Info B VL 7: Input/Output – p.195 Sequentieller Zugriff Öffnen des ZIP-Archivs Sequentielle Suche bis das gewünschte File gefunden ist Extraktion des Files Schliessen des ZIP-Archivs Aufwand: im Mittel halbe Länge des ZIP-Files Info B VL 7: Input/Output – p.196 Random Access Öffnen des ZIP-Archivs Suche des dir-entry und lokalisiere den Eintrag für das gewünschte File Suche rückwärts zur Position des Files Extraktion des Files Schliessen des ZIP-Archivs Info B VL 7: Input/Output – p.197 Weitere Aspekte StreamTokenizer Serializable Pipe-Ströme Info B VL 7: Input/Output – p.198