Datenströme

Datenströme

In Großbuchstaben konveriteren

Öffne eine Textdatei, lese jedes Zeichen ein, konvertiere es Großbuchstaben, und schreibe es in eine neue Datei. Die Methode soll heißen convertFileToUppercase(Path inPath, Path outPath).

Lösung

Kopieren von Dateien mit java.io.FileInputStream, java.io.FileOutputStream

Lösung

Filesplit

Möchte man eine große Datei auf Diskette kopieren, dann besteht bei Dateien über 1,44 MB ein Problem. Man könnte dann aus einer großen Datei mehrere kleine "diskettenkompatible" machen. Schreibe für das Problem ein Programm, welches sich etwa so auf der Kommandozeile aufrufen lässt:

 $ java Filesplit Datei.exe 

War zum Beispiel die Datei 2,44 MB groß, dann könnte das Programm daraus die Dateien Datei1 und Datei2 mit den Größen 1,44 MB und 1 MB machen.

Erweiterung: Teste, ob das Aufzuspaltende eine Datei oder ein Verzeichnis ist. Ist es ein Verzeichnis, so komprimiere es mit dem ZIP-Format und spalte es anschließend auf.

Implementierungsdetails

Betrachte die Implementierung der

Was kann man über die Methode read() in java.io.InputStream und write(...) in java.io.OutputStream sagen? Warum sind einige der Methoden nicht abstrakt? Welche Konsequenz hat dies für die erbenden Klassen?

DataOutputStream

Schreibe mit Hilfe eines java.io.DataOutputStream in einen java.io.FileOutputStream ein paar primitive Datentypen und Zeichenketten.

Implementierung von DataInputStream und DataOutputStream

java.util.zip.GZIPOutputStream

Erstelle eine komprimierte und eine unkomprimierte Datei mit Zahlen von eins bis X, die mit writeLong(...) in einen java.util.zip.GZIPOutputStream geschrieben werden. Vergleiche die Dateigrößen. Ab welchem x lohnt sich eine Kompression?

SnifferOutputStream

Implementiere einen Datenstrom mit einer neuen Klasse SnifferOutputStream, der zwischen anderen Strömen gesetzt werden kann und alle Daten intern speichert. Gebe dem Sniffer eine Methode reset(), die den Inhalt zurücksetzt, und eine Methode getContent(), die den bis dahin gespeicherten Inhalt liefert. Der Sniffer ist von java.io.FilterOutputStream abgeleitet. Einzusetzen ist er etwa wie folgt:

OutputStream sos = new SnifferOutputStream( new FileOutputStream("huhu.txt") ); 
DataOutputStream dos = new DataOutputStream( sos ); 
dos.writeChars( "Hallo Leute" ); 
System.out.println( ((SnifferOutputStream)sos).getContent() );

Lösung

CountedInputStream

Implementiere einen Stream-Filter, der zählt, wie viele Bytes an ihm vorbeirauschen. Der Filter ist von java.io.FilterInputStream abgeleitet.

Lösung

java.io.PrintWriter, java.io.PrintStream und die Filter *

Lege eine Datei mit einem OutputStream an, der von Files.newXXXX(...) kommt. Erzeuge anschließend einen java.io.PrintWriter und schreibe einige Zeilen Text hinein. Lasse try-mit-Ressourcen den Strom korrekt schließen.

java.io.PrintWriter und java.io.DataOutputStream *

Was ist der Unterschied zwischen java.io.PrintStream und dem java.io.DataOutputStream?

java.io.FileWriter und java.io.PrintWriter *

Implementiere eine Klasse, die den java.io.PrintWriter testet. In eine Datei sollen Zahlen von 1 bis 10 geschrieben werden.

Dateien einlesen *

Nutze einen java.io.BufferedReader, um so Zeilen mit Punkten zu lesen. Die Datei sieht etwa so aus:

1,2 
9,43 
2,3 
42,3

Diese Zeilen können mit einem java.util.StringTokenizer auseinander genommen werden. Sie sollen als java.awt.Point-Objekte in eine java.util.ArrayList gehängt werden.

Vermischtes zu Stream-Klassen *

  1. Möchte man keine Datei einladen, weil sie klein ist, so lässt sie sich leicht als Array von Bytes in den Programmtext einfügen. Das folgende C-Programm leistet Ähnliches. Wie sieht eine Variante in Java aus?
    int main(void) { 
      int c,i=0; 
      printf("unsigned char data[]={
        \n"); 
        while((c=getchar())!=EOF) { printf("%d, ", c); 
        if(((++i)&15)==0) printf("\n"); 
      } 
      return 0; 
    }
  2. In der Welt der globalen Kommunikation werden nicht nur Texte verschickt, sondern es kommen immer mehr neue Medien (wie Bilder, Musik, Videos) über die Leitung. Da diese oft binärkodiert sind, müssen sie auf 7 Bit heruntergerechnet werden. Dazu dient das unter UNIX bekannte Programm uuencode und uudecode. Beide Programme sind in C kodiert, die Entsprechendes leisten. Setze eins der Programme in Java um.
  3. Unter der Gnu Public License sind die Quelltexte alle frei verfügbar. Viele Programme für den täglichen Unix-Gebrauch sind dabei in den Dateien textutils, fileutils, binutils und sh-utils enthalten.
    Es folgend einige Programme im Quellcode, die in Java umgesetzt werden sollen: cksum.c, echo.c, head.c, sum.c. (Hier ist natürlich von Vorteil, wenn man die Klasse zum Parsen der Kommandozeilenoptionen schon programmiert hat.)

Welche Klasse für welchen Zweck? *

Welche Streams enthalten andere Streams und wozu? Warum gibt es Byte- und Zeichen-Streams? Zu welcher der beiden Kategorien gehört in in java.lang.System und warum?

Wie erzeuge ich einen Zeichen-Stream, der den Inhalt von mehreren Dateien als einen gepufferten Datenstrom zur Verfügung stellt?

Wie kann man vorgehen, wenn man zusätzlich Daten zurück in den Datenfluss bekommen will?

Die Klasse java.util.StringTokenizer *

Verstehe die Klasse java.util.StringTokenizer, und implementiere ein cut(1)-ähnliches Java-Programm. Das Programm sollte gemäß folgender Syntax aufgerufen werden:

 java Cut [-f field-list] [-d delims] [file ...] 

field-list ist eine durch Kommata getrennte Liste von Ziffern. Jedes Zeichen in dem an das Java-Programm übergebenen String delims wird als ein Feldtrenner betrachtet.

Ein Aufruf könnte wie folgt aussehen:

$ cat input 
eins zwei drei 
eins und:zwei und:drei und: 
$ java Cut -f '2,1,2' -d ': ' input 
zwei eins zwei 
und eins und

Die field-list ist durch Kommata getrennt. Allerdings kann man nicht davon ausgehen, dass alle Elemente in dieser Liste positiv sind, dass die Anzahl kleiner als eine Konstante im Programm und die Syntax des Aufrufs korrekt ist; sprich, das Programm muss mit fehlerhaften Optionen zurechtkommen.

Klasse java.io.StreamTokenizer *

Beschreibe die Methoden quoteChar(int ch), eolIsSignificant(boolean flag) der Klasse java.io.StreamTokenizer an einem Beispiel.

Die sun.io.ByteToCharXXX Klassen *

Mit den Methoden der Klassen ByteToCharXXX- und CharToByteXXX (XXX steht für den Encoding-Namen) der Pakete sun.io sind Konvertierungen von Datentypen möglich. Teste einige der Klassen mit folgendem Gerüst:

Writer out = new OutputStreamWriter(new FileOutputStream("Datei"), "Cp273"); 
out.write("äöüÄÖÜߧ"); 
out.close();

oder

myStringLC = "äöüÄÖÜߧ"; 
myByteArray = myStringLC.getBytes();
String encodedStr273 = new String(myByteArray, "Cp273"); 
System.out.println("encodedStr273 is " + encodedStr273);

Achtung! Wird eine nicht unterstützte Codepage benutzt, z.B. cp274, wird nicht etwa ClassNotFoundException ausgegeben, da es die entsprechende Klasse sun.io.ByteToCharCpxxx bzw. sun.io.CharToByteCPxxx nicht gibt, sondern UnsupportedEncodingException.

In Dateien suchen *

Schreibe eine Klasse JavaGreep, die in einer Datei nach einem Wort sucht. Es soll für jedes Vorkommen die Zeilennummer ausgegeben werden.

FilterStream *

Lies einen Text ein und untersuche die Häufigkeiten der vorkommenden Zeichen.

Komprimierte Dateien

Klasse java.util.zip *

  1. Schreibe ein Programm, das alle Dateien im ZIP-File ausführlich auflistet. Ausführlich heißt: Dateiname, Dateigröße und Datum.
  2. Erlaube die Möglichkeit, dass eine bestimmte angegebene Datei in einem ZIP-Archiv entpackt wird.
    Verwerte dabei die Funktionalität der Klasse java.util.zip.ZipFile und java.util.zip.ZipEntry.
    Beachte, wenn möglich, die Kommandozeilenoptionen der herkömmlichen ZIP-Programme.

Serialisierung

Die Schnittstelle java.io.Serializable *

  1. Schreibe ein Programm, welches ein java.util.HashMap-Objekt serialisiert. Anschließend schreibe ein Programm, welches die java.util.HashMap wieder ausliest.
  2. Wenn man etwas in die Datei schreibt, etwa Long-Objekte, so lohnt sich ab einer bestimmten Anzahl von geschriebenen Elementen die Komprimierung. Schiebe einen java.util.zip.GZIPOutputStream zwischen java.io.FileOutputStream und java.io.ObjectOutputStream .
  3. Ab welcher Zahl wird die Grenze erreicht, sodass sich eine Komprimierung lohnt?
  4. Wie müssten Daten beschaffen sein, damit eine Kompression nicht mehr möglich ist? Schreibe ein Programm, welches Daten produziert, die schlecht zu komprimieren sind
  5. Betrachte die Implementierung der Klasse java.util.ArrayList . Wie wird er serialisiert? Welche Rolle spielt das zu implementierende Interface? Betrachte die Implementierung der Schnittstelle.

Lösung für das Schreiben und Lesen einer komprimierten HashMap