Titel | Inhalt | Suchen | Index | API | Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung |
<< | < | > | >> | Kapitel 19 - Byte-Streams |
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.
Aus InputStream sind einige weitere Klassen direkt abgeleitet. Wie bei den Character-Streams bestimmen sie im wesentlichen die Art bzw. die Quelle der Dateneingabe.
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 |
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. |
|
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.
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 |
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.
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.
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 |
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 |
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 |
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 |
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 |
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. |
|
Titel | Inhalt | Suchen | Index | API | Go To Java 2, Zweite Auflage, Addison Wesley, Version 2.0 |
<< | < | > | >> | © 2000 Guido Krüger, http://www.gkrueger.com |