Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 19 - Byte-Streams

## 19.3 Eingabe-Streams

- 19.3 Eingabe-Streams
  - 19.3.1 Die Basisklasse InputStream
  - 19.3.2 Aus InputStream direkt abgeleitete Klassen
    - FileInputStream
    - ByteArrayInputStream
    - ObjectInputStream
    - SequenceInputStream
    - PipedInputStream
  - 19.3.3 Aus FilterInputStream abgeleitete Klassen
    - BufferedInputStream
    - PushbackInputStream
    - DataInputStream und DataInput
    - CheckedInputStream
    - Entpacken von Dateien

### 19.3.1 Die Basisklasse InputStream

Basis der Eingabe-Streams ist die abstrakte Klasse `InputStream`. Sie stellt folgende Methoden zur Verfügung:

    public abstract int read()
      throws IOException

    public int read(byte[] b)
      throws IOException

    public int read(byte[] b, int off, int len)
      throws IOException

    public long skip(long n)
      throws IOException

    public int available()
      throws IOException

    public void close()
      throws IOException

    public void mark(int readlimit)

    public void reset()
      throws IOException

    public boolean markSupported()
| java.io.InputStream

Die `read`-Methoden dienen dazu, Bytes zu lesen. Sie können entweder einzelne Bytes lesen (die als `int` zurückgegeben werden, dessen obere 3 Byte leer sind) oder ihre Daten direkt in einen Bytearray-Puffer schreiben. Mit `skip` kann eine beliebige Anzahl Bytes übersprungen werden. `available` liefert die Anzahl an Bytes, die ohne Blockieren mindestens gelesen werden können (Vorsicht, manche Implementierungen geben hier nie einen Wert größer als 1 zurück). Mit `close` wird der Eingabe-Stream geschlossen.

Die Methode `markSupported` gibt Auskunft darüber, ob Markieren/Positionieren unterstützt wird. Ist das der Fall, kann mit `mark` die aktuelle Position im Eingabestrom markiert und später mit `reset` dorthin zurückgesprungen werden. Das Argument von `mark` gibt dabei die maximale Anzahl an Zeichen an, die der Eingabestrom sich merken soll.

### 19.3.2 Aus InputStream direkt abgeleitete Klassen

Aus `InputStream` sind einige weitere Klassen direkt abgeleitet. Wie bei den Character-Streams bestimmen sie im wesentlichen die Art bzw. die Quelle der Dateneingabe.

#### FileInputStream

Ein `FileInputStream` stellt einen Byte-Stream zum Lesen aus einer Datei zur Verfügung. Er besitzt einige zusätzliche Konstruktoren:

    public FileInputStream(String name)
      throws FileNotFoundException

    public FileInputStream(File file)
      throws FileNotFoundException

    public FileInputStream(FileDescriptor fdObj)
| java.io.FileInputStream

Um eine Datei zu öffnen, kann entweder ihr Name oder ein dafür konstruiertes `File`-Objekt verwendet werden (siehe Kapitel 21. Existiert die Datei nicht oder kann nicht darauf zugegriffen werden, löst der Konstruktor eine `FileNotFoundException` aus. Mit Hilfe des dritten Konstruktors kann ein `InputStream` zu einer bereits geöffneten Datei erstellt werden.

Das folgende Programm zeigt die Verwendung der Klassen `FileInputStream` und `FileOutputStream` zum Kopieren einer Datei (Vorsicht, eine bereits vorhandene Zieldatei wird ohne Rückfrage überschrieben).

    001 /* FileCopy.java */
    002
    003 import java.io.*;
    004
    005 public class FileCopy
    006 {
    007   public static void main(String[] args)
    008   {
    009     if (args.length != 2) {
    010       System.out.println("java FileCopy inputfile outputfile");
    011       System.exit(1);
    012     }
    013     try {
    014       FileInputStream in = new FileInputStream(args[0]);
    015       FileOutputStream out = new FileOutputStream(args[1]);
    016       byte[] buf = new byte[4096];
    017       int len;
    018       while ((len = in.read(buf)) > 0) {
    019         out.write(buf, 0, len);
    020       }
    021       out.close();
    022       in.close();
    023     } catch (IOException e) {
    024       System.err.println(e.toString());
    025     }
    026   }
    027 }
| FileCopy.java

Listing 19.4: Kopieren einer Datei

#### ByteArrayInputStream

Die Klasse `ByteArrayInputStream` stellt einen Adapter dar, mit dessen Hilfe die Daten aus einem Byte-Array gelesen werden können. Sie besitzt zwei zusätzliche Konstruktoren, in denen die Datenquelle angegeben wird:

    public ByteArrayInputStream(byte[] buf)
    public ByteArrayInputStream(byte[] buf, int offset, int length)
| java.io.ByteArrayInputStream

|  | Im JDK gibt es eine Klasse `StringBufferInputStream`, die einen String als Datenquelle für einen Eingabe-Stream verwendet. Sie ist seit dem JDK 1.1 `deprecated`, weil die Konvertierung von UNICODE-Zeichen in Bytes nicht vollständig korrekt implementiert wurde. An ihrer Stelle ist die Klasse `StringReader` zu verwenden; sie wird in Abschnitt 18.3.2 erklärt. |  |
Hinweis

#### ObjectInputStream

Ein `ObjectInputStream` erlaubt es, primitive Datentypen und Objekte von einem Input-Stream zu lesen. Zwar ist er nicht von `FilterInputStream` abgeleitet, wird aber ebenso verwendet und erwartet im Konstruktor einen `InputStream` als Datenquelle. Die Klasse `ObjectInputStream` ist eine der Säulen des Serialisierungs-APIs in Java und wird in Abschnitt 41.1.3 ausführlich beschrieben.

#### SequenceInputStream

Ein `SequenceInputStream` dient dazu, zwei oder mehr Eingabe-Streams so miteinander zu verbinden, daß die Daten nacheinander aus den einzelnen Streams gelesen werden. Die beteiligten Streams können entweder in einer `Enumeration` oder - wenn es sich um genau zwei von ihnen handelt - direkt an den Konstruktor übergeben werden:

    public SequenceInputStream(Enumeration e)
    public SequenceInputStream(InputStream s1, InputStream s2)
| java.io.SequenceInputStream

#### PipedInputStream

Ein `PipedInputStream` ist das Gegenstück zum `PipedOutputStream`. Beide zusammen bilden eine Pipe zur Kommunikation zweier Threads. Ein Beispiel zur Anwendung der beiden Klassen findet sich in Abschnitt 22.4.4.

### 19.3.3 Aus FilterInputStream abgeleitete Klassen

FilterInputStream

Die aus `InputStream` abgeleitete Klasse `FilterInputStream` ist die Basisklasse aller gefilterten Eingabe-Streams. Diese definieren kein eigenes Eingabegerät, sondern bekommen es beim Instanzieren in Form eines `InputStream`-Arguments übergeben:

    public FilterInputStream(inputStream in)
| java.io.FilterInputStream

Die Aufgabe der aus `FilterInputStream` abgeleiteten Klassen besteht darin, die Lesezugriffe abzufangen, in einer für sie charakteristischen Weise zu verarbeiten und die Daten erst dann an den Aufrufer weiterzugeben.

#### BufferedInputStream

Ein `BufferedInputStream` dient zur Pufferung der Eingabedaten. Er kann insbesondere dann die Performance der Lesezugriffe erhöhen, wenn häufig nur kleine Datenmengen oder einzelne Bytes gelesen werden müssen. Ein `BufferedInputStream` besitzt zwei zusätzliche Konstruktoren, mit denen die Datenquelle und Puffergröße angegeben werden kann:

    public BufferedInputStream(InputStream in)
    public BufferedInputStream(InputStream in, int size)
| java.io.BufferedInputStream

#### PushbackInputStream

Die Klasse `PushbackInputStream` erweitert den Eingabe-Stream um die Fähigkeit, bereits gelesene Zeichen wieder zurückzunehmen. Dazu besitzt sie drei Methoden mit dem Namen `unread`, mit denen einzelne Bytes oder Byte-Arrays wieder zurückgegeben werden können:

    public void unread(int b)
      throws IOException

    public void unread(byte[] b, int off, int len)
      throws IOException

    public void unread(byte[] b)
      throws IOException
| java.io.PushbackInputStream

#### DataInputStream und DataInput

Analog zum `DataOutputStream` gibt es eine Klasse `DataInputStream`, mit der die von diesem geschriebenen Daten eingelesen werden können. Der `DataInputStream` implementiert das Interface `DataInput`, das folgende Methoden definiert:

    void readFully(byte[] b)
      throws IOException
    void readFully(byte[] b, int off, int len)
      throws IOException
    int skipBytes(int n)
      throws IOException
    boolean readBoolean()
      throws IOException
    byte readByte()
      throws IOException
    int readUnsignedByte()
      throws IOException
    short readShort()
      throws IOException
    int readUnsignedShort()
      throws IOException
    char readChar()
      throws IOException
    int readInt()
      throws IOException
    long readLong()
      throws IOException
    float readFloat()
      throws IOException
    double readDouble()
      throws IOException
    String readLine()
      throws IOException
    String readUTF()
      throws IOException
| java.io.DataInput

Die einzelnen Methoden lesen jeweils ein Element des angegebenen Typs, das in dem durch die korrespondierende `write`...-Methode vorgegebenen binären Format vorliegen muß. `readFully` kann dazu verwendet werden, beliebig viele Datenbytes ungeachtet ihres Datentyps einzulesen. `readLine` liest eine Zeile Text aus der Eingabedatei und gibt sie als `String` an den Aufrufer zurück. Da die Eingabe byteweise gelesen wird, werden lediglich UNICODE-Zeichen von \u0000 bis \u00FF korrekt konvertiert. Die `readUnsigned...`-Methoden betrachten die Eingabe als vorzeichenlosen Wert im Bereich von 0 bis 255 (bzw. 0 bis 65535) und geben niemals negative Werte zurück.

Das folgende Programm liest die in Listing 19.2 erzeugten Daten ein und gibt sie auf der Console aus:

    001 /* Listing1905.java */
    002
    003 import java.io.*;
    004
    005 public class Listing1905
    006 {
    007   public static void main(String[] args)
    008   {
    009     try {
    010       DataInputStream in = new DataInputStream(
    011                            new BufferedInputStream(
    012                            new FileInputStream("test.txt")));
    013       System.out.println(in.readInt());
    014       System.out.println(in.readInt());
    015       System.out.println(in.readDouble());
    016       System.out.println(in.readUTF());
    017       System.out.println(in.readUTF());
    018       in.close();
    019     } catch (IOException e) {
    020       System.err.println(e.toString());
    021     }
    022   }
    023 }
| Listing1905.java

Listing 19.5: Verwendung der Klasse DataInputStream

#### CheckedInputStream

Die Klasse `CheckedInputStream` aus dem Paket `java.util.zip` dient dazu, die Prüfsumme zu einer Menge von Eingabedaten direkt beim Einlesen zu berechnen. Sie stellt einen Konstruktor zur Verfügung, mit dem das gewünschte Prüfsummenverfahren angegeben werden kann, und besitzt eine Methode `getChecksum`, mit der die Prüfsumme ermittelt werden kann:

    public CheckedInputStream(InputStream in, Checksum cksum)

    public Checksum getChecksum()
| java.util.zip.CheckedInputStream

Das im Konstruktor erforderliche Objekt muß das Interface `Checksum` implementieren. Mit den beiden Klassen `CRC32` und `Adler32` stehen im JDK zwei vordefinierte Implementierungen zur Verfügung. Das folgende Programm berechnet die Adler-32-Prüfsumme zu der in der Kommandozeile angegebenen Datei:

    001 /* Listing1906.java */
    002
    003 import java.io.*;
    004 import java.util.zip.*;
    005
    006 public class Listing1906
    007 {
    008   public static void main(String[] args)
    009   {
    010     if (args.length != 1) {
    011       System.out.println("Usage: java Listing1906 file");
    012       System.exit(1);
    013     }
    014     try {
    015       CheckedInputStream in = new CheckedInputStream(
    016         new FileInputStream(args[0]),
    017         new Adler32()
    018       );
    019       byte[] buf = new byte[4096];
    020       int len;
    021       while ((len = in.read(buf)) > 0) {
    022         //nichts
    023       }
    024       System.out.println(in.getChecksum().getValue());
    025       in.close();
    026     } catch (IOException e) {
    027       System.err.println(e.toString());
    028     }
    029   }
    030 }
| Listing1906.java

Listing 19.6: Berechnung der Adler-32-Prüfsumme

#### Entpacken von Dateien

Analog zur Klasse `DeflaterOutputStream` gibt es im Paket `java.util.zip` eine Klasse `InflaterInputStream` zum Entpacken von gepackten und/oder komprimierten Dateien. Die daraus abgeleiteten Klassen `GZIPInputStream` und `ZipInputStream` können direkt zum Entpacken von GZIP- und ZIP-Dateien verwendet werden.

Das folgende Programm zeigt, wie die mit dem Programm Zip.java aus Listing 19.3 gepackten Dateien wieder entpackt und dekomprimiert werden können:

    001 /* Unzip.java */
    002
    003 import java.io.*;
    004 import java.util.zip.*;
    005
    006 public class Unzip
    007 {
    008   public static void main(String[] args)
    009   {
    010     if (args.length != 1) {
    011       System.out.println("Usage: java Unzip zipfile");
    012       System.exit(1);
    013     }
    014     try {
    015       byte[] buf = new byte[4096];
    016       ZipInputStream in = new ZipInputStream(
    017                           new FileInputStream(args[0]));
    018       while (true) {
    019         //Nächsten Eintrag lesen
    020         ZipEntry entry = in.getNextEntry();
    021         if (entry == null) {
    022           break;
    023         }
    024         //Beschreibung ausgeben
    025         System.out.println(
    026           entry.getName() +
    027           " (" + entry.getCompressedSize() + "/" +
    028           entry.getSize() + ")"
    029         );
    030         //Ausgabedatei erzeugen
    031         FileOutputStream out = new FileOutputStream(
    032           entry.getName()
    033         );
    034         int len;
    035         while ((len = in.read(buf)) > 0) {
    036           out.write(buf, 0, len);
    037         }
    038         out.close();
    039         //Eintrag schließen
    040         in.closeEntry();
    041       }
    042       in.close();
    043     } catch (IOException e) {
    044       System.err.println(e.toString());
    045     }
    046   }
    047 }
| Unzip.java

Listing 19.7: Entpacken eines ZIP-Archivs

|  |  |  | Das hier vorgestellte Programm dient - wie sein Gegenstück Zip.java - vor allem als "Proof of Concept". Einerseits bietet es nur einen Bruchteil der üblicherweise von einem Entpacker erwarteten Features (es werden beispielsweise keine Unterverzeichnisse automatisch erzeugt). Andererseits überschreibt es vorhandene Ausgabedateien ohne Vorwarnung. Der Umgang mit dem Programm sollte also mit der notwendigen Umsichtigkeit erfolgen. |  |
Warnung

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de