Ein- und Ausgabe ist im Paket java.io implementiert. Die gliedert sich in die Hauptbereiche
Die Klassen aus java.io benutzt man meist nicht einzeln sondern
in Kombination.
Byte-Ströme dienen zur Speicherung binärer Daten
Byte-Strom-Eingabe wird von der abstrakten Klasse InputStream realisiert:
Beispiel: Zähle die Zeichen in einer Datei
import java.io.*; class CountChars { public static void main(String argv[]) throws IOException { InputStream in; if (argv.length != 0) in = new FileInputStream(argv[0]); else in = System.in; int ch; int total=0; while ((ch = in.read()) != -1) total++; System.out.println("Number of chars: " + total); } }
Neben dem oben verwendeten FileInputStream existieren:
Daten aus einem Byte-Array im Speicher lesen.
Teil des Object Serialization
APIs (neu in Java1.1) zur Ausgabe von Objekten
(siehe Seite ).
implementiert die Eingabe-Seite einer Pipe.
konkateniert mehrere Eingabeströme zu
einem (siehe Seite ).
Lesen aus StringBuffer-Objekten (veraltet, daher: deprecated-Meldung).
import java.io.*; class Concatenate { public static void main(String[] a) { ListOfFiles mylist = new ListOfFiles(a); try { SequenceInputStream s = new SequenceInputStream(mylist); int c; while ((c = s.read()) != -1) System.out.write(c); s.close(); } catch (IOException e) { System.err.println ("Concatenate: " + e); } } }
Hier ist die notwendige Enumeration:
import java.util.*; import java.io.*; class ListOfFiles implements Enumeration { String[] listOfFiles; int current = 0; ListOfFiles(String[] listOfFiles) { this.listOfFiles = listOfFiles; } public boolean hasMoreElements() { return current < listOfFiles.length; } public Object nextElement() { InputStream is = null; if (!hasMoreElements()) throw new NoSuchElementException(); else { try { String next = listOfFiles[current++]; is = new FileInputStream(next); } catch (FileNotFoundException e) {} } return is; } }
Filterströme werden mit anderen Eingabeströmen verbunden, um die eingelesenen Daten weiterzubearbeiten.
Neben der Verwendung dieser Filter-Strom-Klassen aus der Bibliothek
besteht die Möglichkeit, eigene Filterklassen zu schreiben.
Benutzung am Beispiel von DataInputStream:
import java.io.*; class CountLines { public static void main(String a[]) throws IOException { InputStream in; if (a.length != 0) in = new FileInputStream(a[0]); else in = System.in; DataInputStream dis = new DataInputStream(in); String inp; int total = 0; while (( inp = dis.readLine()) != null) total++; System.out.println("Number of lines: " + total); } }
DataInputStream liefert Einlesemethoden für alle gängigen Datentypen, u.a.:
Beispiel:
public class InFile extends DataInputStream { public InFile(String filename) throws FileNotFoundException { super( new BufferedInputStream( new FileInputStream(filename))); } }
Beispiel:
import java.io.*; class BinIO { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("try.txt"); FileOutputStream fos = new FileOutputStream("try_cp.txt"); int c; while ((c = fis.read()) != -1) { fos.write(c); } fis.close(); fos.close(); } catch (IOException e) { System.err.println("BinIO: " + e); } } }
Die Klasse PrintStream liefert Methoden zur Ausgabe der textuellen Darstellung der Java-Grundtypen.
Da sie eher zur Zeichenausgabe (siehe Seite ) gehört,
wird die Klasse nicht mehr benutzt. Statt dessen kommt
die Klasse PrintWriter (siehe Seite
) zum Einsatz.
Einzige Bedeutung:
Die beiden Standard-Ausgabedateien System.out
und System.err sind vom Typ PrintStream.
Im Gegensatz zu den Byte-Strömen, die bis Java1.0 auch zur
Zeichenausgabe verwendet wurden, garantieren die Zeichen-Strom-Klassen
die korrekte Umsetzung von Unicode gemäß der lokalen
Gegebenheiten.
Zeichen-Strom-Eingabe wird von der abstrakten Klasse Reader realisiert:
import java.io.*; public class ReadLines { public static void main (String a[]) { BufferedReader din = new BufferedReader( new InputStreamReader(System.in)); String line; do { try { line = din.readLine(); } catch(IOException ioe) { break; } if (line == null) // end of stream break; System.out.println(line); } while (true); } }
Die Klasse StringReader bietet die Standard-Funktionalität der Reader-Klassen, wobei die Lesequelle ein String ist.
Beispiel:
import java.io.*; class StrRead { public static void main(String[] a) throws IOException { StringReader inp = new StringReader(a[0]); int c; while((c = inp.read()) != -1) System.out.println((char)c); } }
Beispiel:
import java.io.*; class SquareList { public static void main(String[] a) throws IOException { PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter("square.list"))); for (int i = 0; i < Integer.parseInt(a[0]); i++) { out.print(i); out.print(": "); out.println(Math.sqrt(i)); } out.close(); } }
Ziel der RandomAccessFile-Klasse ist die freie Positionierung von Schreib-/Lese-Zeigern an beliebigen Datei-Positionen.
Beispiel:
import java.io.*; class RandAcc { public static void main(String[] a) throws IOException { RandomAccessFile rf; rf = new RandomAccessFile( "try.dat", "rw"); rf.writeChars("Jva"); rf.close(); rf = new RandomAccessFile( "try.dat", "rw"); rf.seek(2); // Position 2 rf.writeChars("ava"); rf.close(); BufferedReader din = new BufferedReader( new FileReader("try.dat")); // schreibe "Java": System.out.println(din.readLine()); } }
Die Klasse File bietet nützliche Methoden, um Datei- und Verzeichnisnamen zu manipulieren.
Außerdem erlauben viele der Konstruktoren der IO-Klassen ein
File-Argument:
File ipf = new File("input.dat"); FileInputStream fis = new FileInputStream(ipf);
Einige nützliche Methoden
Beispiel: Löschen von Dateien
import java.io.*; public class Delete // Lösche eine Datei { public static void main(String[] args) { try { delete(args[0]);} catch (IllegalArgumentException e) { System.err.println( e.getMessage() +": " + args[0]); } } public static void delete(String name) { File f = new File(name); if (!f.exists()) fail("No such file or directory"); if (!f.canWrite()) fail("Write protected"); if (f.isDirectory()) { String[] files = f.list(); if (files.length > 0) fail("Directory not empty"); } if (!f.delete()) // jetzt endlich fail("Deletion failed"); } protected static void fail(String msg) throws IllegalArgumentException { throw new IllegalArgumentException(msg); } }
Der StreamTokenizer erkennt 4 einfache Symbolklassen
und stellt deren Werte in öffentlichen Attributen zur Verfügung.
Kleines Beispiel:
static double sumStream(InputStream in) throws IOException { StreamTokenizer nums = new StreamTokenizer(in); double result = 0.0; while (nums.nextToken() == StreamTokenizer.TT_NUMBER) result += nums.nval; return result; }
Serializable ist ein (``Marker''-) Interface in java.io, das dazu benutzt wird, Klassen zu kennzeichnen, von denen Objekte in Binärdateien abgelegt werden sollen (neu in Java1.1 ).
Serialisierung ist wichtig in Client/Server Anwendungen, für
Cut-and-Paste, für Software-Komponenten ( Beans)
und die Speicherung bereits initialisierter Applets.
Beispiel: Serialisierung von baumstrukturierten Objekten
Eine Klasse für Suchanfragen
Markiert als Serializable
import java.io.*; abstract class SuchAnfrage implements Serializable {abstract public void print(); }
Ein einzelner Suchbegriff
import java.io.*; public class Begriff extends SuchAnfrage { String begr; Begriff(String b) { begr = b; } public void print() { System.out.print(begr + " "); } }
Und-Verknüpfung von Suchbegriffen
import java.io.*; public class Und extends SuchAnfrage { SuchAnfrage sl; SuchAnfrage sr; public Und(SuchAnfrage sl, SuchAnfrage sr) { this.sl = sl; this.sr = sr; } public void print() { System.out.print("( "); sl.print(); System.out.print("UND "); sr.print(); System.out.print(") "); } }
Oder-Verknüpfung von Suchbegriffen
import java.io.*; public class Oder extends SuchAnfrage { SuchAnfrage sl; SuchAnfrage sr; public Oder(SuchAnfrage sl, SuchAnfrage sr) { this.sl = sl; this.sr = sr; } public void print() { System.out.print("( "); sl.print(); System.out.print("ODER "); sr.print(); System.out.print(") "); } }
Negation von Suchbegriffen
import java.io.*; public class Nicht extends SuchAnfrage { SuchAnfrage s; Nicht(SuchAnfrage s) { this.s = s; } public void print() { System.out.print("NICHT "); s.print(); } }
Das Hauptprogramm: Serialisierung von Suchbegriffen
Zunächst wird eine Suchanfrage konstruiert:
(Java UND NICHT (C++ ODER Smalltalk))
import java.io.*; public class Main { public static void main(String [] a) throws IOException, ClassNotFoundException { SuchAnfrage s; s = new Und( new Begriff("Java"), new Nicht( new Oder( new Begriff("C++"), new Begriff("Smalltalk") ) ) );
// Objekte rausschreiben ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("such.dat")); out.writeObject(s); out.close(); // Objekte einlesen ObjectInputStream in = new ObjectInputStream( new FileInputStream("such.dat")); SuchAnfrage wiederda = (SuchAnfrage) in.readObject(); wiederda.print(); System.out.println(); } }