Ein- und Ausgabe Für die Ein- und Ausgabe von Daten gibt es eine Reihe von Möglichkeiten. Beispiele hierfür sind: • Eingabe als Parameter auf der Kommandozeile • Eingabe über die Tastatur • Eingabe aus einer oder mehreren Dateien • Eingabe über GUI-Widgets Im Prinzip auch möglich: • Eingabe im Programmtext Dies ist aber nur sinnvoll, wenn es wenige Eingaben gibt. 7. Klassen und Methoden zur Ein- und Ausgabe 7-1 Ein- und Ausgabe • Ausgabe auf dem Bildschirm • Ausgabe in eine oder mehrere Dateien • Ausgabe über GUI-Widgets Einige dieser Möglichkeiten haben wir bereits besprochen. In diesem Kapitel wiederholen wir einige Konzepte und sehen uns weitere Beispiele an. Es gibt noch weitere Möglichkeiten. Zum Beispiel können Daten durch die Kommunikation zwischen Prozessen erhalten oder weitergeleitet werden. Die Programmierung von parallelen Prozessen und grafischen Oberflächen behandeln wir in Programmieren II. 7. Klassen und Methoden zur Ein- und Ausgabe 7-2 Ein-/Ausgabe • Einige Klassen und Methoden zur Ein-/Ausgabe haben wir ja schon kennengelernt. • In diesem Kapitel wiederholen wir einige dieser Klassen und Methoden und sehen uns nur einige weitere Klassen und Methoden für die Ein- und Ausgabe an. • Java bietet sehr viele weitere Klassen und Methoden für die Ein- und Ausgabe von Daten an. 7. Klassen und Methoden zur Ein- und Ausgabe 7-3 Grundlagen • Der Zugriff auf Daten kann wahlfrei oder sequenziell erfolgen. Für den sequenziellen Zugriff wurde in Java das Konzept der Streams eingeführt. • Ein Stream ist ein abstraktes Konzept, das Zeichen der Reihe nach von einem imaginären Eingabegerät lesen oder auf ein imaginäres Ausgabegerät schreiben kann. • Erst konkrete Unterklassen binden die Zugriffsroutinen an echte Ein- und Ausgabegeräte wie ◦ ◦ ◦ ◦ Tastatur oder Bildschirm, Dateien, Strings und Kommunikationskanäle. 7. Klassen und Methoden zur Ein- und Ausgabe 7-4 Streams • Streams können verkettet oder verschachtelt werden. • Durch die Verkettung von Streams ist es möglich, mehrere Streams zu einem zusammenzufassen, der die Streams nacheinander verarbeitet. • Die Schachtelung von Streams erlaubt z. B. die Konstruktion von Filtern, die beispielsweise Zeichen puffern oder Eingabezeilen zählen. • Beide Konzepte sind durch Klassen realisiert und können daher vom Benutzer modifiziert und erweitert werden. • Die Klassen zur Ein- und Ausgabe befinden sich im Paket java.io (Nicht alle). 7. Klassen und Methoden zur Ein- und Ausgabe 7-5 Streams • Byte-Streams Jede Transporteinheit ist 8 Bit lang. • Character-Streams Character-Streams verwenden Unicode-Zeichen der Länge 16 Bit. • Für die Umwandlung beider Stream-Arten ineinander wurden Brückenklassen eingeführt. 7. Klassen und Methoden zur Ein- und Ausgabe 7-6 Zugriff auf Dateien Wenn wir die Daten einer Datei bearbeiten wollen, so müssen wir • die Datei öffnen, • die Datenelemente lesen und verarbeiten bzw. die Elemente in der gewünschten Reihenfolge ausgeben und • die Datei wieder schließen. Gegebenenfalls muss die Datei vorher erzeugt werden. 7. Klassen und Methoden zur Ein- und Ausgabe 7-7 Ein- und Ausgabe • In Java existieren eine Vielzahl von Klassen und Methoden zum wahlfreien und sequenziellen Zugriff auf Dateien und andere Ein- oder Ausgabemedien. • Wir können hier nur eine kleine Auswahl von ihnen näher betrachten und diese exemplarisch an typischen Beispielen erläutern. • Für weitere Informationen sollten Sie die angegebene Literatur zu Rate ziehen. 7. Klassen und Methoden zur Ein- und Ausgabe 7-8 Stream-Basisklassen Die folgenden abstrakten Klassen bilden die Basis für die streambasierte Ein-Ausgabe: Byte Byte Character Character Ausgabe Eingabe Ausgabe Eingabe OutputStream InputStream Writer Reader Viele der Unterklassen existieren sowohl für "Byte" als auch für "Character". 7. Klassen und Methoden zur Ein- und Ausgabe 7-9 Stream-Basisklassen Stream-Klassen sind hierarchisch organisiert: • Writer (abstract) ◦ BufferedWriter ◦ OutputStreamWriter ∗ FileWriter • Reader (abstract) ◦ BufferedReader ◦ InputStreamReader ∗ FileReader 7. Klassen und Methoden zur Ein- und Ausgabe 7-10 Die Klasse PrintStream Die Klasse PrintStream bietet Methoden zum Schreiben der Werte vieler Datentypen: class PrintStream { ... print( ... ); println( ... ); printf( ... ); ... } Einige Anwendungen kennen wir schon lange: System.out.println(...) java.lang.System.out.println(...) 7. Klassen und Methoden zur Ein- und Ausgabe 7-11 Die Klasse PrintStream Ableitungshierarchie der Klasse PrintStream: • Object ◦ OutputStream (abstract) ∗ FilterOutputStream - PrintStream 7. Klassen und Methoden zur Ein- und Ausgabe 7-12 Die Klasse System • Die Klasse System enthält eine Reihe systemnaher Attribute und Methoden. Sie kann nicht instanziiert werden. • Attribute: PrintStream out, InputStream in und PrintStream err • Methoden (Auswahl): ◦ static void exit(int status) Ein Aufruf dieser Methode beendet den gegenwärtigen Lauf der Java Virtual Machine. Das Argument dient als Status-Code. Gemäß Vereinbarung bedeutet ein von 0 verschiedener Wert einen Fehler. ◦ static Properties getProperties() static String getProperty(string key) 7. Klassen und Methoden zur Ein- und Ausgabe 7-13 Die Klasse System class System { // Der Standard-Ausgabe-Stream; eine Klassenvariable public static final PrintStream out; // Der Standard-Eingabe-Stream; eine Klassenvariable public static final InputStream in; // Der Standard-Fehler-Stream; eine Klassenvariable public static final PrintStream err; ... } 7. Klassen und Methoden zur Ein- und Ausgabe 7-14 Die Klasse System Systembedingte Eigenschaften werden durch die Properties der Klasse System zur Verfügung gestellt. static String getProperty(string key); String ls = System.getProperty("line.separator"); Einige Eigenschaften: s. nächste Folie. 7. Klassen und Methoden zur Ein- und Ausgabe 7-15 Properties der Klasse System Version: Firma: Home: Betriebssystem: Architektur: Version: Benutzername: Home-Verzeichnis: Verzeichnis: Zeilentrennzeichen: Dateitrennzeichen: Pfadtrennzeichen: 7. Klassen und Methoden zur Ein- und Ausgabe java.version java.vendor java.home os.name os.arch os.version user.name user.home user.dir line.separator file.separator path.separator 7-16 Ausgabe auf Datei String ls = System.getProperty("line.separator"); String hello = "Hallo Java!"; FileWriter f1; try { f1 = new FileWriter("hallo.txt"); f1.write(hello + ls + hello + ls); f1.close(); } catch (IOException e) { System.out.println("Fehler beim Erstellen der Datei!"); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-17 Eingabe von der Tastatur import java.io.*; ... throws IOException { int a, b, c; BufferedReader din = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Bitte a eingeben: "); a = Integer.parseInt(din.readLine()); System.out.println("Bitte b eingeben: "); b = Integer.parseInt(din.readLine()); c = a + b; System.out.println("a + b = " + c); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-18 Puffern der Ein- bzw. Ausgabe • Das Puffern der Ein- bzw. Ausgabe verringert i. Allg. die Anzahl der externen Zugriffe und erhöht somit die Effizienz. • Die Methode readLine() der Klasse BufferedReader liest eine ganze Zeile. 7. Klassen und Methoden zur Ein- und Ausgabe 7-19 Lesen aus einer Datei FileReader f; int c; try { f = new FileReader("..."); while ((c = f.read()) != -1) { System.out.print((char) c); } f.close(); } catch (IOException e) { System.out.println("Fehler beim Lesen der Datei!"); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-20 Die Klasse File • Im Paket java.io existiert die Klasse File. • Objekte dieser Klasse repräsentieren Dateien oder Verzeichnisse. • Konstruktoren: ◦ File(String pathname) ◦ File(String parent, String child) ◦ File(File parent, String child) • Beispiele: ◦ new File("Test.java") ◦ new File("..", "Test.java") 7. Klassen und Methoden zur Ein- und Ausgabe 7-21 Anlegen und Löschen einer Datei • Das Anlegen einer Datei besteht aus zwei Schritten: 1. Überprüfen, ob die Datei bereits existiert. 2. Falls nein, Datei anlegen. Wenn mehrere Prozesse parallel arbeiten, dann müssen diese Schritte als Transaktion ablaufen. • boolean createNewFile() throws IOException • void deleteOnExit() 7. Klassen und Methoden zur Ein- und Ausgabe 7-22 Zugriff auf den Pfadnamen • String getName() • String getPath() • String getAbsolutePath() • String getParent() 7. Klassen und Methoden zur Ein- und Ausgabe 7-23 Informationen über eine Datei • boolean exists() • boolean isFile() boolean isDirectory() • boolean canWrite() boolean canRead() • String[] list() • File[] listFiles() File[] listFiles(FileFilter filter) FileFilter ist eine Schnittstelle. Es ist die Methode boolean accept(File pathname) zu implementieren. 7. Klassen und Methoden zur Ein- und Ausgabe 7-24 Ändern von Verzeichniseinträgen • boolean mkdir() • boolean mkdirs() Creates the directory named by this abstract pathname, including any necessary but nonexistent parent directories. • boolean renameTo(File dest) • boolean delete() 7. Klassen und Methoden zur Ein- und Ausgabe 7-25 Rekursiver Durchlauf eines Verzeichnisses import java.io.*; public interface DirectoryVisitor { public void enterDirectory(File dir); public void leaveDirectory(File dir); public void visitFile(File file); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-26 Rekursiver Durchlauf eines Verzeichnisses import java.io.*; public class DirectoryPrintVisitor implements DirectoryVisitor { String indent = ""; public void enterDirectory(File dir) { System.out.println(indent + "[" + dir.getName() + "]"); indent += " "; } public void leaveDirectory(File dir) { indent = indent.substring(2); } public void visitFile(File file) { System.out.println(indent + file.getName()); } } 7. Klassen und Methoden zur Ein- und Ausgabe 7-27 Rekursiver Durchlauf eines Verzeichnisses static void traverse(File dir, DirectoryVisitor visitor) { visitor.enterDirectory(dir); File[] entries = dir.listFiles() for (int i = 0; i < entries.length; ++i) { if (entries[i].isDirectory()) { traverse(entries[i], visitor); } else { visitor.visitFile(entries[i]); } } visitor.leaveDirectory(dir); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-28 Rekursiver Durchlauf eines Verzeichnisses Listing des Ordners tmp im Home-Verzeichnis: String fs = System.getProperty("file.separator"), file = System.getProperty("user.home") + fs + "tmp"; traverse(new File(file), new DirectoryPrintVisitor()); 7. Klassen und Methoden zur Ein- und Ausgabe 7-29 Formatierte Ausgabe for (double x = 0.5; x<=1.4; x+=0.1) { System.out.println(x+": "+Math.sin(x)); } 0.5: 0.479425538604203 0.6: 0.5646424733950354 0.7: 0.644217687237691 0.7999999999999999: 0.7173560908995227 0.8999999999999999: 0.7833269096274833 0.9999999999999999: 0.8414709848078964 1.0999999999999999: 0.8912073600614353 1.2: 0.9320390859672263 1.3: 0.963558185417193 7. Klassen und Methoden zur Ein- und Ausgabe 7-30 Formatierte Ausgabe for (double x = 0.5; x<=1.4; x+=0.1) { System.out.printf("%4.2f: %9.6f%n", x, Math.sin(x)); } 0.50: 0.60: 0.70: 0.80: 0.90: 1.00: 1.10: 1.20: 1.30: 0.479426 0.564642 0.644218 0.717356 0.783327 0.841471 0.891207 0.932039 0.963558 7. Klassen und Methoden zur Ein- und Ausgabe 7-31 Formatierte Ausgabe • Die Methode printf ermöglicht eine formatierte Ausgabe. • %4.2f, %9.6f und %n sind Formatstrings. Formatstrings beginnen mit % und enden mit einem Konversionszeichen, zum Beispiel f. • Zwischen dem Prozentzeichen und dem Konversionszeichen können weitere Steuerzeichen stehen, die die Formatierung steuern. Beispielsweise bedeutet 9.6, dass die Ausgabe mindestens 9 Zeichen lang ist und 6 Nachkommastellen besitzt. • Durch weitere Angaben kann beispielsweise festgelegt werden, ob die Ausgabe links- oder rechtsbündig erfolgt, ob führende Nullen ausgegeben werden oder ob positive Vorzeichen dargestellt werden. 7. Klassen und Methoden zur Ein- und Ausgabe 7-32 Formatstring %b %c %d %o %x %X %f %e %g %s %n %% ... boolescher Wert Zeichen ganzzahliger Wert in Dezimaldarstellung ganzzahliger Wert in Oktaldarstellung ganzzahliger Wert in Hexadezimaldarstellung (Kleinbuchstaben) ganzzahliger Wert in Hexadezimaldarstellung (Großbuchstaben) Fließkommazahl Fließkommazahl, Exponentenschreibweise Fließkommazahl, gemischte Schreibweise Strings, Objekte neue Zeile das Prozentzeichen ... 7. Klassen und Methoden zur Ein- und Ausgabe 7-33 Steuerzeichen + 0 , ( m .p linksbündige Ausgabe immer mit Vorzeichen ausgeben führende Nullen ausgeben Zahlen mit Tausendermarkierung ausgeben negative Zahlen in Klammern ausgeben, kein Vorzeichen Mindestbreite bei %g die Anzahl der Nachkommastellen Beispiele: %9.6f %+05d Fließkommazahl mit mindestens 9 Stellen, davon 6 Nachkommastellen ganzzahliger Wert in Dezimaldarstellung, mindestens 5 Stellen, führende Nullen und Vorzeichen werden ausgegeben 7. Klassen und Methoden zur Ein- und Ausgabe 7-34 Formatierte Ausgabe • Die Methode PrintStream printf(String format, Object... args) gehört zur Klasse PrintStream. • Die Methode static String format(String format, Object... args) gehört zur Klasse String. • Einzelheiten zur formatierten Ausgabe können in der Beschreibung der Klasse java.util.Formatter nachgelesen werden. 7. Klassen und Methoden zur Ein- und Ausgabe 7-35 Die Klasse Scanner • Die Klasse Scanner stellt einen einfachen Text-Scanner zur Verfügung, mit dessen Hilfe primitive Datentypen und Strings analysiert werden können. • Diese Klasse befindet sich im Paket java.util: import java.util.Scanner • Wir erläutern die Anwendung dieser Klasse an drei Beispielen: 1. Eingabe von der Tastatur, 2. Eingabe durch eine Zeichenkette, 3. Eingabe aus einer Datei. • Weitere Einzelheiten, insbesondere die Verwendung regulärer Ausdrücke als Trennzeichen, können der Java-Dokumentation entnommen werden. 7. Klassen und Methoden zur Ein- und Ausgabe 7-36 Die Klasse Scanner Eingabe von der Tastatur: Scanner sc = new Scanner(System.in); int i, j; System.out.print("Bitte geben Sie die erste Zahl ein: "); i = sc.nextInt(); System.out.print("Bitte geben Sie die zweite Zahl ein: "); j = sc.nextInt(); System.out.printf("Die Summe der Zahlen beträgt %d.%n", i+j); 7. Klassen und Methoden zur Ein- und Ausgabe 7-37 Die Klasse Scanner Eingabe durch eine Zeichenkette: int i, j; Scanner sc = new Scanner("34 45"); i = sc.nextInt(); j = sc.nextInt(); System.out.printf("Die Summe der Zahlen beträgt %d.%n", i+j); 7. Klassen und Methoden zur Ein- und Ausgabe 7-38 Die Klasse Scanner Eingabe aus einer Datei: public static void main(String[] args) throws IOException { Scanner sc = new Scanner(new File("zahlen.txt")); double k = 0.0; while (sc.hasNextDouble()) { k += sc.nextDouble(); } System.out.printf("Die Summe der Zahlen beträgt %.4f.%n", k); } 7. Klassen und Methoden zur Ein- und Ausgabe 7-39 Ein-/Ausgabe Wie schon erwähnt: Java bietet sehr viele weitere Klassen und Methoden für die Ein- und Ausgabe von Daten an. Beispiel: Sehen Sie sich die Beschreibung der Klassen • • • • Console, Path, Paths und Files in der Java-Api an. 7. Klassen und Methoden zur Ein- und Ausgabe 7-40