Datenströme

Datenströme

Zufallsfelder

Besorge von Files einen OutputStream und generiere 100 MiB Zufallsdaten, also Bytes von 0x00 bis 0xFF.

Bonus. Finde unter Linux ein Programm, mit dem man ein (nicht notwendigerweise grafisches) Histrogramm herstellen kann und sehen kann, dass die Daten gleichverteilt sind.

Python nach Java konvertieren

Ein Python-Programm erzeugt ein interessantes Bild so:

import Image, ImageDraw
 
image = Image.new("RGB", (256, 256))
drawingTool = ImageDraw.Draw(image)
 
for x in range(256):
for y in range(256):
        drawingTool.point((x, y), (0, x^y, 0))
 
del drawingTool
image.save("xorpic.png", "PNG")

Konvertiere das Programm nach Java, sodass statt der PNG-Datei eine SVG-Datei erzeugt wird, in der jeder Pixel ein 1x1 großer SVG-Rectangle ist:

<!DOCTYPE html>
<html><body><svg width="256" height="256">
 <rect x="10" y="10" width="1" height="1" style="fill:rgb(0,29,0);" />
</svg></body></html>

In Großbuchstaben konvertieren

Öffne eine Textdatei, lies 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 

Ist zum Beispiel die Datei 2,44 MiB groß, dann wird das Programm daraus die Dateien Datei.exe.1 und Datei.exe.2 mit den Größen 1,44 MiB und 1 MiB 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.

Bonus: Implementiere die Optionen, die das Unix-Programm split hat.

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.

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