Grundlagen der Informatik 1

Werbung
Technische Universität Darmstadt
Telecooperation/RBG
Grundlagen der Informatik 1
Thema 20: Ströme und Ein-/Ausgabe in Java
Dr. Guido Rößling
Copyrighted material; for TUD student use only
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Inhaltsverzeichnis
• Einführung in Eingabe-/Ausgabe-Ströme und Java
Ein-/Ausgabe (Input/Output, I/O)
• Einblick in Prozessströme
• Schachtelung von Stromobjekten und das
Decorator-Muster
• Selbstdefinierte Ströme, StreamTokenizer und
wahlfreier Zugriff
Grundlagen der Informatik I: T20
2
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Eingabe /Ausgabe (Input / Output, I/O)
• Bislang:
– Eingabedaten sind entweder fest im Quelltext codiert oder werden
als Parameter beim Programmstart von der Konsole übergeben
• define in Racket
• Variablendeklaration und Initialisierung in Java
• Tatsächliche Parameterwerte in Funktionsaufrufen von Racket
• args Parameter in main
– Ausgaben des Programms wurden auf dem Bildschirm ausgegeben
• Probleme:
– „Closed World“
• keine Interaktion mit der Außenwelt
• Keine Einflussnahme auf den Programmablauf nach dem Start
– Ergebnisse können nicht dauerhaft gespeichert werden
• Diese Vorlesung widmet sich anderer Möglichkeiten der Ein-/
Ausgabe in Java
Grundlagen der Informatik I: T20
3
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
I/O-Ströme
• Verschiedene Quellen/Senken für die Daten
–
–
–
–
Tastatureingabe („Standard I/O“)
Datei(en) auf dem lokalen Rechner („File I/O“)
Datei(en)/Prozess(e) im Netzwerk („Network I/O“)
Hauptspeicher („Memory I/O“)
• Um einheitlich Daten auf unterschiedliche „Datenbehälter“ ein-/
auszugeben, verwendet Java das Konzept der „Streams“ (Ströme)
– Eingabe- und Ausgabeströme (E/A, engl. I/O)
• Datenströme als eine Abstraktion von I/O “Geräten“
– Verstecken Details über die Implementierung / Funktionsweise der
einzelnen I/O-Geräte vor dem Java Programmierer
• Tastatur, Datei, anderes Programm, Netz, Hauptspeicher, …
– Stellen Java-Programmen einheitliche Schnittstellen zum Lesen bzw.
Schreiben von Daten zur Verfügung
– Das Java Programm “spricht“ mit Java I/O Objekten
Grundlagen der Informatik I: T20
4
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
I/O-Ströme
• Um Daten von einer externen Datenquelle zu lesen, öffnet
ein Java-Programm einen Eingabestrom und liest die Daten
seriell (nacheinander) ein:
• Um Daten in eine externe Senke zu schreiben, öffnet ein
Java-Programm einen Ausgabestrom und schreibt die
Daten seriell
Grundlagen der Informatik I: T20
5
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Ströme und verzögerte Listen
• Das Konzept der Ströme ist allgemeiner und nicht nur für I/O
geeignet
• Die Idee haben wir bereits in Racket kennen gelernt
– Verzögerte Listen
– Möglichkeit, „virtuelle“ Listen zu erzeugen
– Wir konnten transparent Daten mit first und rest verknüpfen
• Diese Idee passt sehr gut zu I/O
– Input: Lese den Eingabewert beim Zugriff auf das nächste
Listenelement
– Output: Beim Erweitern der Liste Ausgabewert schreiben
– Eingabestrom à verzögerte Liste ohne cons
– Ausgabestrom à verzögerte Liste ohne first/rest
Grundlagen der Informatik I: T20
6
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Vordefinierte Ströme in java.io
• Zwei Klassifizierungen von Datenströmen:
– Nach dem Datentyp
– Nach der Struktur der Ströme
Grundlagen der Informatik I: T20
7
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Klassifizierung der Ströme
• Nach dem Datentyp
– Zeichenströme lesen / schreiben char (16-bit Unicode
Zeichensatz)
– Byteströme lesen / schreiben byte (8-bit)
• Werden zum Lesen bzw. Schreiben von Binärdaten, z.B. Bildern,
benutzt
• Nach der Struktur der Ströme:
– Datensenkeströme: Daten werden direkt von „physikalischer“
Datenquelle gelesen bzw. auf „physikalische“ Datensenke
geschrieben
– Prozessströme: Daten werden von anderen Strömen gelesen
bzw. auf andere Ströme geschrieben
• Daten werden nach dem Lesen bzw. vor dem Schreiben gefiltert,
gepuffert, bearbeitet, usw.
Grundlagen der Informatik I: T20
8
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Hierarchie der Datenströme in Java
• Zeichenströme
– java.io.Reader/java.io.Writer stellen die
Schnittstelle und eine partielle Implementierung von
Zeichenströmen zur Verfügung
– Subklassen von Reader/Writer fügen neues Verhalten
hinzu bzw. ändern dieses.
• Byteströme
– java.io.InputStream/java.io.OutputStream:
gemeinsame Schnittstelle und partielle Implementierung
für alle Ströme zum Lesen bzw. Schreiben von Bytes
• Alle anderen Byteströme sind Unterklassen davon
Grundlagen der Informatik I: T20
9
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Hierarchie der Zeichenströme (Auszug)
Reader
StringReader
Die Klassen in
schattierten Kästchen
sind Prozessströme
InputStreamReader
FileReader
FilterReader
PushbackReader
BufferedReader
LineNumberReader
Writer
StringWriter
OutputStreamWriter
FileWriter
FilterWriter
BufferedWriter
PrintWriter
Grundlagen der Informatik I: T20
10
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Hierarchie der Byteströme (Auszug)
FileInputStream
StringBufferInputStream
PipedInputStream
InputStream
ByteArrayInputStream
Die Klassen in
schattierten Kästchen
sind Prozessströme
BufferedInputStream
ObjectInputStream
LineNumberInputStream
FilterInputStream
PushbackInputStream
SequenceInputStream
DataInputStream
FileOutputStream
PipedOutputStream
OutputStream
ByteArrayOutputStream
FilterOutputStream
ObjectOutputStream
BufferedOutputStream
PrintStream
DataOutputStream
Grundlagen der Informatik I: T20
11
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Datensenke-Ströme: Überblick
Senke Typ
Hauptspeicher
Pipe
Datei
Zeichenströme
Byteströme
CharArrayReader,
CharArrayWriter
StringReader,
StringWriter
PipedReader,
PipedWriter
ByteArrayInputStream,
ByteArrayOutputStream
StringBufferInputStream
FileReader,
FileWriter
FileInputStream,
FileOutputStream
PipedInputStream,
PipedOutputStream
• CharArrayReader/CharArrayWriter
ByteArrayInputStream/ByteArrayOutputStream
• Lesen / Schreiben von / auf Arrays
• StringReader/StringWriter, StringBufferInputStream
– Lesen / Schreiben von / auf Strings im Hauptspeicher
• FileReader/FileWriter, FileInputStream/FileOutputStream
– Lesen / Schreiben von / auf Dateien
Grundlagen der Informatik I: T20
12
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Gemeinsame Muster der I/O-Ströme
• Lesen/Schreiben von/auf Strömen haben unabhängig von
Datentyp und Quelle bzw. Senke die gleiche Form
• Lesen
• Öffne einen Strom
• Ströme werden beim Erzeugen automatisch geöffnet
• Lese Daten, solange nötig und es noch Daten gibt
• Schließe den Strom
• Bei Beenden des Lesens bzw. Schreibens sollte der Strom durch
close() geschlossen werden!
• Schreiben
• Öffne einen Strom
• Solange es noch Daten gibt, schreibe Daten
• Schließe den Strom
Grundlagen der Informatik I: T20
13
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
I/O-Oberklassen
• Nutze I/O Ströme nur über allgemeines Interface
• Information Hiding durch Subtyppolymorphie
InputStream
public int read()
public int read(byte[] bbuf)
public int read(byte[] bbuf, int offset, int len)
Reader
public int read()
public int read(char[] cbuf)
public int read(char[] cbuf, int offset, int len)
OutputStream
public int write(int b)
public int write(byte[] bbuf)
public int write(byte[] bbuf, int offset, int len)
Writer
public int write(int c)
public int write(char[] cbuf)
public int write(char[] cbuf, int offset, int len)
Grundlagen der Informatik I: T20
14
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Die Klasse java.io.Reader
public
public
public
public
...
int read(char[] c) throws IOException
long skip(long n) throws IOException
void reset() throws IOException
int close() throws IOException
• public abstract int read(char[] c) throws
IOException
– Liest die nächsten Unicode-Zeichen im Strom in ein Array
– Gibt die Anzahl der gelesenen Zeichen zurück oder -1, falls das
Ende der Datei erreicht wurde („EOF“)
– IOException bei allen anderen Problemen
• Z.B. Strom bereits geschlossen, Netzwerkverbindung verloren
Für weitere Details siehe API Spezifikation
http://download.oracle.com/javase/6/docs/api/
Grundlagen der Informatik I: T20
15
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Java Dokumentation
Grundlagen der Informatik I: T20
16
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Java Dokumentation
Grundlagen der Informatik I: T20
17
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Dateiströme
• Dateiströme sind Ein-/Ausgabe-Ströme, deren Quellen/
Senken Dateien im Dateisystem sind
– FileReader / FileWriter für Lesen / Schreiben von
Zeichen aus/in Dateien
–
Analog dazu: FileInputStream, FileOutputStream für
Lesen / Schreiben von Bytes von/in Dateien
• Ein Dateistrom kann erzeugt werden, indem man die Quellebzw. Senke-Datei durch eines der folgenden Objekte als
Parameter des Strom-Konstruktors übergibt
–
–
–
Dateiname (String)
Datei-Objekt (java.io.File)
Dateibeschreibung (java.io.FileDescriptor)
Grundlagen der Informatik I: T20
18
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Die Klasse java.io.FileReader
• Beispiel: Ausgeben eines Dateiinhalts auf den Bildschirm (Ausgabe erfolgt
als Integer-Werte!) und Zeichen von 'a' bis 'z' in eine Datei schreiben
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class ReadWriteFile {
// Konstruktor etc.
public void readFrom(String fileName) throws IOException {
FileReader in = new FileReader(fileName);
int b;
while ((b = in.read()) != -1) System.out.print(b);
in.close();
}
}
public void writeAToZ(String filename) throws IOException {
FileWriter out = new FileWriter(filename);
for (char c = 'a'; c <= 'z'; c++) out.write(c);
out.close();
}
// main etc.
Grundlagen der Informatik I: T20
19
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Inhaltsverzeichnis
• Einführung in Ein-/Ausgabe-Ströme und Java Ein-/
Ausgabe (Input/Output, I/O)
• Einblick in Prozessströme
• Schachtelung von Stromobjekten und das
Decorator-Muster
• Selbstdefinierte Ströme, StreamTokenizer und
wahlfreier Zugriff
Grundlagen der Informatik I: T20
20
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Prozess-Ströme
• Ein Prozess-Strom enthält einen anderen (Daten- oder
Prozess-)Strom
– Dieser dient als Quelle bzw. Senke
• Prozess-Ströme ändern Daten oder bieten Funktionalität
–
–
–
–
Zwischenspeichern (Puffern) von Daten
Zählen der gelesenen/geschriebenen Zeilen
Konvertierung zwischen Byte und Zeichen
Kompression, …
Prozess-Datenstrom Originaler Datenstrom
Datensenke
Datenquelle
Grundlagen der Informatik I: T20
21
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Prozess-Ströme
Aufgabe
Zeichenströme
Byteströme
Filtern
FilterReader,
FilterWriter
FilterInputStream,
FilterOutputStream
Puffern
BufferedReader,
BufferedWriter
BufferedInputStream,
BufferedInputStream
byte à char
Byte / Zeichen InputStreamReader,
Konvertierung OutputStreamWriter
Zählen
LineNumberReader
Unterstützung
für Datentypen
Rückgängig
PushbackReader
machen
Ausgeben
PrintWriter
char à byte
LineNumberInputStream
DataInputStream,
DataOutputStream
PushbackInputStream
PrintStream
Grundlagen der Informatik I: T20
22
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Die Wurzel der Prozess-Ströme
• FilterReader/FilterWriter bzw.
FilterInputStream/FilterOutputStream sind
Superklassen für alle Prozessströme
• Kapseln einen internen Strom in
• Defaultimplementierung einer Operation op:
delegiere op weiter an in (in.op())
• Konkrete Unterklassen redefinieren diese
Funktionalität
Grundlagen der Informatik I: T20
23
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Java Dokumentation
Grundlagen der Informatik I: T20
24
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Pufferströme
• Ein Pufferstrom kapselt einen anderen Datenstrom und einen
internen Puffer
• Beim ersten Lesen wird der Puffer vollständig gefüllt
– Weitere Lese-Operationen liefern Bytes vom Puffer zurück, ohne
vom unterliegenden Strom tatsächlich zu lesen
– Bei leerem Puffer wird erneut vom unterliegenden Strom gelesen
• Beim Schreiben werden die Daten zuerst in dem internen Puffer
gespeichert, bevor sie in den unterliegenden Strom geschrieben
werden
– Nur wenn der Puffer voll ist, wird auf den unterliegenden Strom
geschrieben
– Sowie bei explizitem Aufruf der Methoden flush() oder close()
Grundlagen der Informatik I: T20
25
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Pufferströme
• BufferedReader und BufferedWriter bieten die StandardSchnittstelle und Implementierung für Zeichenströme mit
Pufferung an
– Unterklassen von Reader bzw. Writer
• BufferedInputStream und BufferedOutputStream bieten
die Standard-Schnittstelle und Implementierung für Byteströme
mit Pufferung an
– Unterklassen von FilterInputStream bzw.
FilterOutputStream
Grundlagen der Informatik I: T20
26
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Pufferströme
Datensenke
BufferedWriter
Programm
write
write
b
bbuf
write bbuf
write bbuf
flush
Grundlagen der Informatik I: T20
27
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Pufferströme: Performanz
Lesen einer 2.5 MB-Datei (x: Puffergröße, y: Zeit [ms]
Puffergröße Time[ms]
Grundlagen der Informatik I: T20
1
6433
2
3453
4
1935
8
988
16
471
32
365
64
363
128
87
256
327
512
65
1024
162
2048
214
4096
260
8192
61
16384
166
32768
159
28
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
DataInputStream / DataOutputStream
• Diese Ströme ermöglichen das Lesen/Schreiben von primitiven Java
Datentypen in einem maschinenunabhängigen Format.
• Ein DataOutputStream wird verwendet, um Daten zu schreiben,
die später von einem DataInputStream gelesen werden sollen.
FilterInputStream
FilterOutputStream
<<interface>>
DataInput
DataInputStream
readBoolean(): boolean
readByte(): byte
readShort() : short
readChar() : char
readInt() : int
readFloat() : float
<<interface>>
DataOutput
DataOutputStream
writeBoolean(boolean) : void
writeByte(byte) : void
writeShort(short) : void
writeChar(char) : void
writeInt(int) : void
writeFloat(float) : void
Grundlagen der Informatik I: T20
29
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Datenströme: Beispiel
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class DataStreamExample {
String fileName = "hello.txt";// ein Dateiname
// ein paar Methoden
public void writeData() throws IOException {
FileOutputStream fos = new FileOutputStream(filename);
DataOutputStream out = new DataOutputStream(fos);
out.writeInt(9);
out.writeDouble(Math.PI);
out.writeBoolean(true);
out.close();
}
// weitere Methoden
public void readData() throws IOException {
FileInputStream fis = new FileInputStream(fileName);
DataInputStream in = new DataInputStream(fis);
int i = in.readInt();
double d = in.readDouble();
boolean b = in.readBoolean();
in.close();
System.out.println("Gelesen: "+ i + ", " + d + ", und " + b+ ".");
}
}
Grundlagen der Informatik I: T20
30
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Standard-I/O
• Im Paket java.lang gibt es die Klasse System mit den
folgenden Klassenvariablen:
System.in
System.out
System.err
Standardeingabe (Tastatur)
Standardausgabe (Bildschirm)
Fehlermeldungen (Bildschirm)
• System.in ist ein Objekt vom Typ InputStream
– Stellt read() zum byte-weisen Lesen von Bytes
von der Tastatur zur Verfügung
• System.out, System.err sind vom Typ PrintStream
– Bieten print() und println() zur Datenausgabe an
Grundlagen der Informatik I: T20
31
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
PrintStream
• Ermöglicht das einfache Schreiben von
diversen Datentypen in einer üblichen
Repräsentation
• Wirft niemals eine IOException
– Auftretende Exceptions setzen ein
internes Flag, das durch die
checkError Methode getestet
werden kann
• Alle Zeichen, die mit einem
PrintStream geschrieben werden,
werden mit dem Standardzeichensatz
der Plattform konvertiert
– PrintWriter sollte in Situationen
eingesetzt werden, in denen
Zeichen (anstelle von Bytes)
geschrieben werden
FilterOutputStream
PrintStream
print(boolean) : void
print(double) : void
print(char) : void
print(double) : void
print(float) : void
...
println(Object): void
println(String): void
...
Grundlagen der Informatik I: T20
32
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Inhaltsverzeichnis
• Einführung in Ein-/Ausgabe-Ströme und Java Ein-/
Ausgabe (Input/Output, I/O)
• Einblick in Prozessströme
• Schachtelung von Stromobjekten und das
Decorator-Muster
• Selbstdefinierte Ströme, StreamTokenizer und
wahlfreier Zugriff
Grundlagen der Informatik I: T20
33
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Verschachtelung der Ströme
• Ströme können ineinander verschachtelt werden
àAbstraktionsebenen, bei denen unterliegende
„primitive“ Ströme von umschließenden („höheren“,
komfortableren) Strömen benutzt werden („Prozessströme“)
BufferedOutputStream
FileOutputStream
ZipOutputStream
Datensenke,
z.B. Datei
// erzeugt gepufferten, komprimierenden Dateiausgabestrom
OutputStream out = new FileOutputStream(filename);
out = new BufferedOutputStream(out);
out = new ZipOutputStream(out);
// … mehr Eigenschaften koennen dynamisch hinzugefuegt werden
// Die Stromeigenschaften sind unsichtbar fuer Klienten
Grundlagen der Informatik I: T20
34
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Architektur von Java Streams
• Die Technik, mit der erreicht wird, dass Ströme
beliebig zur Laufzeit kombiniert werden können,
ist nicht nur im Kontext von Strömen von
Interesse.
–
Generelle Technik, um Objekte dynamisch mit
Features zu erweiterten
• In der Softwaretechnik werden solche Techniken
in der Form so genannter Entwurfsmuster (design
patterns) dokumentiert.
–
–
Wieder verwendbare, dokumentierte Designideen
Mehr in der Hauptstudiumsvorlesung „SE Design“
• Die oben genannte Technik bei Streams ist als
„Decorator Pattern“ bekannt.
Grundlagen der Informatik I: T20
35
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Inhaltsverzeichnis
• Einführung in Ein-/Ausgabe-Ströme und Java Ein-/
Ausgabe (Input/Output, I/O)
• Einblick in Prozessströme
• Schachtelung von Stromobjekten und das
Decorator-Muster
• Selbstdefinierte Ströme, StreamTokenizer und
wahlfreier Zugriff
Grundlagen der Informatik I: T20
36
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Selbstdefinierte Prozessströme
• Oft möchten Programmierer eigene Ströme definieren, die Daten
filtern und/oder verarbeiten, die von einem anderen Strom
gelesen/geschrieben werden
• Eigene Filterung oder Verarbeitung kann implementiert werden,
indem man von FilterReader/FilterInputStream bzw.
FilterWriter/FilterOutputStream erbt
• Es folgt ein Beispiel eines selbstdefinierten Filterstroms auf
Datenströmen, der alle Zeilen im unterliegenden Strom
herausfiltert, die einen bestimmten Substring enthalten
à Unix "grep" Befehl
Grundlagen der Informatik I: T20
37
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Selbstdefinierte Prozessströme
import java.io.BufferedReader;
import java.io.FilterReader;
import java.io.IOException;
class GrepReader extends FilterReader {
String substring;
BufferedReader in;
GrepReader(BufferedReader reader, String pattern) {
super(reader);
in = reader;
substring = pattern;
}
// return the next line containing the search pattern
String readLine() throws IOException {
String line;
while (((line = in.readLine()) != null) &&
(line.indexOf(substring) == -1)) ;
return line;
}
}
Grundlagen der Informatik I: T20
38
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Selbstdefinierte Prozessströme
import java.io.*;
public class Grep {
public static void main(String[] args) {
if ((args.length == 0) || (args.length > 2)) {
System.out.println("Usage: java Grep <substring> [<filename>]");
System.exit(0);
}
try {
Reader d;
if (args.length == 2)
d = new FileReader(args[1]);
else
d = new InputStreamReader(System.in);
GrepReader g = new GrepReader(new BufferedReader(d), args[0]);
String line;
while ((line = g.readLine()) != null) System.out.println(line);
g.close();
}
catch (IOException e) {
System.err.println(e);
}
}
}
Durchsuchter
Datenstrom
Grundlagen der Informatik I: T20
Zu findendes
Muster
39
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Wahlfreier Zugriff
• Bisher: Ströme, deren Inhalt nur in einer
sequentiellen Weise gelesen bzw. geschrieben
werden kann
• Sequentielle Dateien passen gut zu sequentiellen
Speichermedien, z.B. Magnetbänder
• Random Access Files erlauben nicht-sequentielle
(wahlfreie) Zugriffe auf den Inhalt einer Datei
Grundlagen der Informatik I: T20
40
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Warum wahlfreier Zugriff?
• Gegeben ein Dateiarchiv in .zip Format:
– Zip-Archive bestehen aus Dateien und sind meist
komprimiert, um Speicher zu sparen
– Außer Dateien haben Zip-Archive ganz zum Schluss zusätzlich
einen so genannten Dir-Eintrag (von Directory, engl.
Verzeichnis)
– Hier wird gespeichert, welche Dateien enthalten sind und wo
die einzelnen Dateien innerhalb des Archivs anfangen
• Aufgabe: eine bestimmte Datei aus dem Archiv extrahieren
Grundlagen der Informatik I: T20
41
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Darum wahlfreier Zugriff!
• Verfahren für einen sequentiellen Strom
– Suche durch das ganze Archiv, bis die gewünschte Datei lokalisiert ist
– Extrahiere die Datei
• Im Durchschnitt wird die Hälfte der Einträge im Archiv gelesen,
bevor die gewünschte Datei gefunden ist
• Strom mit wahlfreiem Zugriff
– Springe zum Dir-Eintrag und lese den Eintrag der gesuchten Datei
– Springe rückwärts zu der Position der Datei
– Extrahiere die Datei
• Man muss genau zwei Einträge lesen: dir-entry and file
• Das Verfahren ist also wesentlich effizienter!
Grundlagen der Informatik I: T20
42
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Wahlfreier Zugriff in Java
• Realisiert durch die Klasse RandomAccessFile
• Kann für Lesen und Schreiben benutzt werden implementiert Schnittstellen DataInput und
DataOutput
• Ähnelt FileInputStream und FileOutputStream,
indem man ein RandomAccessFile auf eine Datei öffnet
und beim Erzeugen den Dateinamen oder ein File-Objekt
als Parameter übergibt:
• Außerdem muss beim Erzeugen spezifiziert werden, ob
die Datei nur zum Lesen oder auch zum Schreiben
geöffnet wird
– Man muss eine Datei lesen können, um auf sie schreiben zu
können
Grundlagen der Informatik I: T20
43
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Wahlfreier Zugriff in Java
• Erzeugen eines RandomAccessFile, um die Datei
„random.txt“ zu lesen:
– new RandomAccessFile("random.txt", "r");
• Erzeugen eines RandomAccessFile, um die Datei
„random.txt“ zu lesen und zu schreiben:
– new RandomAccessFile("random.txt", "rw");
• Nachdem die Datei geöffnet ist, kann mit den read und
write-Operationen gelesen bzw. geschrieben werden
Grundlagen der Informatik I: T20
44
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Wahlfreier Zugriff in Java
• RandomAccessFile unterstützt einen Datei-Zeiger
– indiziert die aktuelle Dateiposition
• Beim Erzeugen ist der Datei-Zeiger 0 - der Anfang der Datei
• Aufrufe von read / write- Operationen verschieben
den Datei-Zeiger automatisch um die Anzahl
der gelesenen bzw. geschriebenen Bytes
• RandomAccessFile unterstützt zusätzlich Operationen zum
Manipulieren des Zeigers:
– public int skipBytes(int n) throws IOException
• Verschiebt den Zeiger vorwärts um n Bytes
– public native void seek(long pos) throws
IOException
• Positioniert den Zeiger genau vor das Byte an der Stelle pos
– public native long getFilePointer() throws
IOException
• Gibt die aktuelle Position in der Datei zurück
Grundlagen der Informatik I: T20
45
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Stromverarbeitung mit StreamTokenizer
• java.io.StreamTokenizer unterstützt die Zerlegung
von Zeichenströmen in Symbole („Tokens“)
• Lesen des nächsten Tokens durch nextToken()
– Überspringt Whitespace („leere Zeichen“)
• Was als Whitespace angesehen wird, ist konfigurierbar
– Der Typ des gelesenen Tokens wird über das Attribut ttype
abgefragt
• Die Tokenarten werden auf der folgenden Folie vorgestellt
Grundlagen der Informatik I: T20
46
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
StreamTokenizer: Tokenarten
• StreamTokenizer.TT_NUMBER: Zahl erkannt, nval
enthält die Zahl
• StreamTokenizer.TT_WORD: Wort erkannt, sval enthält
das Wort
• StreamTokenizer.TT_EOL: Zeilenende ist erkannt
– Wird nur dann als Token erkannt, wenn der Tokenizer entsprechend
konfiguriert wurde (eolIsSignificant(true))
• StreamTokenizer.TT_EOF – Dateiende wurde erreicht
• „Sonstiges“ – ttype codiert ein Zeichen, etwa '$', ';'
Grundlagen der Informatik I: T20
47
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Anpassung von StreamTokenizer
• public void wordChars(int low, int hi)
– Definieren, was als Wortbestandteil gelten soll
– Alle Zeichen im Intervall [low, hi] zählen als Wortbestandteile
• public void whitespaceChars(int low, int hi)
– Definieren von Leerzeichen
– Alle Zeichen im Intervall [low, hi] zählen als „Leerzeichen“
• public void eolIsSignificant(boolean flag)
– Definieren, ob Zeilenende relevant ist
• public void quoteChar(int quoteChar)
– Definieren von Anführungszeichen
• Zahlreiche andere Features – bitte in die Doku sehen!
Grundlagen der Informatik I: T20
48
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
StreamTokenizer: Anwendungsbeispiel
• Eine Teeliste mit der folgenden
Struktur soll geparst werden:
– Jeder Tee steht in einer eigenen
Zeile
• Zeilenende ist relevant!
– Die Teenamen sind durch
Anführungszeichen „gequotet“
– Hinter dem Teenamen stehen der
Reihe nach
• Dauer des Ziehenlassens [s]
• Anzahl Teelöffel pro Liter
• Diese Einträge sind jeweils
durch Leerzeichen getrennt
• Mittels StreamTokenizer ist
das Parsen einfach!
"Ali Babas 40 Düfte" 180 5
"Asatsuyu" 90 7
"Generic Black Tea" 180 5
"Caramel" 120 6
"Ceylon Pekoe" 120 6
"China Jasmin" 120 6
"Cool Down" 1273 0
"Einer für alle" 540 6
"Erdbeer-Sahne" 120 6
"Erfrischungskräutertee" 480 6
"Früchtepfund" 420 6
Grundlagen der Informatik I: T20
49
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
StreamTokenizer: Anwendungsbeispiel
public void parseTeas(Reader r) throws IOException {
StreamTokenizer stok = new StreamTokenizer(r);
stok.eolIsSignificant(true); // EOL melden
stok.quoteChar('\"'); // " als Worttrenner
int token = 0;
String teaName = null;
int nrSpoons, nrSecs, coolDown;
}
while ((token = stok.nextToken()) != StreamTokenizer.TT_EOF) {
teaName = stok.sval; // 1. Token
token = stok.nextToken();
nrSecs = (int)stok.nval; // 2. Token
token = stok.nextToken();
nrSpoons = (int)stok.nval; // 3. Token
token = stok.nextToken(); // must be EOL
System.out.println(teaName +":" + nrSpoons
+" Loeffel, Ziehzeit: " + nrSecs);
}
Normalerweise sollte man vor einer Zuweisung den Typ prüfen!
Grundlagen der Informatik I: T20
50
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Scanner
• Seit Java 1.5 dient java.util.Scanner zum Parsen
• Scanner kann auf einem Stream, File, … geöffnet werden
– Typische Anwendung:
• Scanner sc = new Scanner(System.in);
• Scanner bietet mehrere hilfreiche Methoden:
– String next(); // liefert das nächste Token
– x nextX(); // für x = byte, double, float, int, long, short, Line
• Wirft InputMismatchException falls falscher Typ gelesen
– boolean hasNextX(); // Gleiches x wie oben
• Prüft, ob das nächste Element zu Typ X passt
– Die Grenzelemente sind redefinierbar, sogar auf Worte
– Auch reguläre Ausdrücke können verwendet werden
• Bitte schauen Sie in die API Doku für mehr Details
Grundlagen der Informatik I: T20
51
Dr. G. Rößling
Prof. Dr. M. Mühlhäuser
RBG / Telekooperation
©
Was noch?
• Verschlüsselte Dateien, komprimierte Dateien, Dateien übers
Internet, ...
• Ausnahmen! Alle I/O Operationen sind potentielle Quelle von
Ausnahmen!
– Deswegen immer (siehe T16):
try {
Befehle mit I/O
}
catch (IOException e) {
e.printStackTrace();
}
Grundlagen der Informatik I: T20
52
Herunterladen