Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger

Java ist auch eine Insel von Christian Ullenboom
Programmieren für die Java 2-Plattform in der Version 5 (Tiger-Release)
Buch: Java ist auch eine Insel
gp Kapitel 12 Datenströme und Dateien
  gp 12.1 Datei und Verzeichnis
    gp 12.1.1 Dateien und Verzeichnisse mit der Klasse File
    gp 12.1.2 Dateieigenschaften und -attribute
    gp 12.1.3 Dateien berühren, neue Dateien anlegen
    gp 12.1.4 Umbenennen und Verzeichnisse anlegen
    gp 12.1.5 Die Wurzel aller Verzeichnisse/Laufwerke
    gp 12.1.6 Verzeichnisse listen und Dateien filtern
    gp 12.1.7 Dateien und Verzeichnisse löschen
    gp 12.1.8 Implementierungsmöglichkeiten für die Klasse File
    gp 12.1.9 Verzeichnisse nach Dateien rekursiv durchsuchen
    gp 12.1.10 Sicherheitsprüfung
    gp 12.1.11 Namen der Laufwerke
    gp 12.1.12 Locking
  gp 12.2 Dateien mit wahlfreiem Zugriff
    gp 12.2.1 Ein RandomAccessFile öffnen
    gp 12.2.2 Aus dem RandomAccessFile lesen
    gp 12.2.3 Schreiben
    gp 12.2.4 Die Länge des RandomAccessFile
    gp 12.2.5 Hin und her in der Datei
  gp 12.3 Stream-Klassen und Reader/Writer
    gp 12.3.1 Die abstrakten Basisklassen
    gp 12.3.2 Übersicht über Ein-/Ausgabeklassen
  gp 12.4 Binäre Ein-/Ausgabe-Klassen InputStream und OutputStream
    gp 12.4.1 Die Klasse OutputStream
    gp 12.4.2 Ein Datenschlucker
    gp 12.4.3 Anwendung der Klasse FileOutputStream
    gp 12.4.4 Die Eingabeklasse InputStream
    gp 12.4.5 Anwenden der Klasse FileInputStream
    gp 12.4.6 Kopieren von Dateien
  gp 12.5 Daten filtern durch FilterInputStream und FilterOutputStream
    gp 12.5.1 Der besondere Filter PrintStream
    gp 12.5.2 Die Schnittstelle Appendable
    gp 12.5.3 System.in und System.out
  gp 12.6 Besondere OutputStream- und InputStream-Klassen
    gp 12.6.1 Bytes in den Strom schreiben mit ByteArrayOutputStream
    gp 12.6.2 Bytes in den Strom schreiben mit ByteArrayInputStream
    gp 12.6.3 Ströme zusammensetzen mit SequenceInputStream
  gp 12.7 Ressourcen wie Grafiken aus dem Klassenpfad und aus Jar-Archiven laden
  gp 12.8 Die Unterklassen von Writer
    gp 12.8.1 Die abstrakte Klasse Writer
    gp 12.8.2 Datenkonvertierung durch den OutputStreamWriter
    gp 12.8.3 In Dateien schreiben mit der Klasse FileWriter
    gp 12.8.4 StringWriter und CharArrayWriter
    gp 12.8.5 Writer als Filter verketten
    gp 12.8.6 Gepufferte Ausgabe durch BufferedWriter
    gp 12.8.7 Ausgabemöglichkeiten durch PrintWriter erweitern
    gp 12.8.8 Daten mit FilterWriter filtern
  gp 12.9 Die Klassen um Reader
    gp 12.9.1 Die abstrakte Basisklasse Reader
    gp 12.9.2 Automatische Konvertierungen mit dem InputStreamReader
    gp 12.9.3 Dateien lesen mit der Klasse FileReader
    gp 12.9.4 StringReader und CharArrayReader
  gp 12.10 Die Filter für Zeichenströme
    gp 12.10.1 Gepufferte Eingaben mit der Klasse BufferedReader
    gp 12.10.2 LineNumberReader zählt automatisch Zeilen mit
    gp 12.10.3 Eingaben filtern mit der Klasse FilterReader
    gp 12.10.4 Daten mit der Klasse PushbackReader zurücklegen
  gp 12.11 Kommunikation zwischen Threads mit Pipes
    gp 12.11.1 PipedOutputStream und PipedInputStream
    gp 12.11.2 PipedWriter und PipedReader
  gp 12.12 Datenkompression
    gp 12.12.1 Die Java-Unterstützung beim Komprimieren und Zusammenpacken
    gp 12.12.2 Datenströme komprimieren
    gp 12.12.3 Zip-Archive
    gp 12.12.4 Jar-Archive
  gp 12.13 Prüfsummen
    gp 12.13.1 Die Schnittstelle Checksum
    gp 12.13.2 Die Klasse CRC32
    gp 12.13.3 Die Adler32-Klasse
  gp 12.14 Persistente Objekte und Serialisierung
    gp 12.14.1 Objekte speichern mit der Standard-Serialisierung
    gp 12.14.2 Objekte über die Standard-Serialisierung lesen
    gp 12.14.3 Die Schnittstelle Serializable
    gp 12.14.4 Nicht serialisierbare Attribute mit transient aussparen
    gp 12.14.5 Das Abspeichern selbst in die Hand nehmen
    gp 12.14.6 Tiefe Objektkopien
    gp 12.14.7 Versionenverwaltung und die SUID
    gp 12.14.8 Wie die ArrayList serialisiert
    gp 12.14.9 Serialisieren in XML-Dateien
    gp 12.14.10 XML-API von Sun
  gp 12.15 Zugriff auf SMB-Server
    gp 12.15.1 jCIFS
  gp 12.16 Tokenizer
    gp 12.16.1 StreamTokenizer
    gp 12.16.2 CSV (Comma Separated Values)-Dateien verarbeiten
  gp 12.17 Die Logging-API


Galileo Computing

12.13 Prüfsummedowntop

Damit Fehler bei Dateien oder bei Übertragungen von Daten auffallen, wird eine Prüfsumme (engl. checksum) gebildet. Prüfsummen werden vor der Übertragung erstellt und mit dem Paket versendet. Der Empfänger berechnet diese Prüfsumme neu und vergleicht sie mit dem übertragenen Wert. Stimmt der berechnete Wert mit dem übertragenen überein, so war die Übertragung höchstwahrscheinlich in Ordnung. Es ist ziemlich unwahrscheinlich, dass eine Änderung von Bits nicht auffällt. Genauso werden korrupte Archive erkannt. Pro Datei wird eine Prüfsumme berechnet. Soll die Datei entpackt werden, so errechnen wir wieder die Summe. Ist diese fehlerhaft, so muss die Datei fehlerhaft sein. (Wir wollen hier ausschließen, dass zufälligerweise die Prüfsumme fehlerhaft ist, was natürlich auch passieren kann.)


Galileo Computing

12.13.1 Die Schnittstelle Checksum  downtop

Wir finden Zugang zur Prüfsummenberechnung über die Schnittstelle java.util.zip. Checksum, die für ganz allgemeine Prüfsummen steht. Eine Prüfsumme wird entweder für ein Feld oder ein Byte berechnet. Checksum liefert die Schnittstelle zum Initialisieren und Auslesen von Prüfsummen, die von konkreten Prüfsummen-Klassen implementiert werden muss.



interface java.util.zip.  Checksum  

gp  long getValue()
Liefert die aktuelle Prüfsumme.
gp  void reset()
Setzt die aktuelle Prüfsumme auf einen Anfangswert.
gp  void update( int b )
Aktualisiert die aktuelle Prüfsumme mit b.
gp  void update( byte b[], int off, int len )
Aktualisiert die aktuelle Prüfsumme mit dem Feld.

Bisher finden sich in den Java-Bibliotheken nur die Klassen CRC32 und Adler32, die von der Schnittstelle Checksum Gebrauch machen. Aber mit wenig Aufwand lässt sich beispielsweise eine Klasse schreiben, die die einfache Paritätsüberprüfung übernimmt. Dies können wir zum Beispiel be der Übertragung von Daten an der seriellen Schnittstelle verwenden. (Glücklicherweise ist dies im Fall der seriellen Schnittstelle schon in der Hardware implementiert.)


Galileo Computing

12.13.2 Die Klasse CRC32  downtop

Oft werden Prüfsummen durch Polynome gebildet. Die Prüfsumme, die für Dateien verwendet wird, heißt CRC32, und das bildende Polynom lautet:

x32  +x26  +x23  +x22  +x16  +x12  +x11  +x10  +x+x+x+x+x+x+1

Nun lässt sich zu einer 32-Bit-Zahl eine Prüfsumme berechnen, die genau für diese vier Bytes steht. Damit bekommen wir aber noch keinen ganzen Block kodiert. Um das zu erreichen, berechnen wir den Wert eines Zeichens und Xor-verknüpfen den alten CRC-Wert mit dem neuen. Jetzt lassen sich beliebig Blöcke sichern. Ohne groß zu überlegen, dürfte klar sein, dass viel Zeit für die Berechnung aufgewendet werden muss. Bisher ist der mathematische Algorithmus auch nicht in Java, sondern in C implementiert.


Beispiel   CRC32 berechnet eine Prüfsumme entweder für ein Byte oder für ein Feld.

Kurz und knapp sieht ein Programm zur Berechnung von Prüfsummen für Dateien dann so aus (in ist ein InputStream-Objekt):


CRC32 crc = new CRC32();
byte ba[] = new byte[(int)in.available()];
in.read( ba );
crc.  update  ( ba );
in.close();

CRC32 implementiert nicht nur alle Methoden, sondern fügt noch zwei Funktionen und natürlich einen Konstruktor hinzu.



class java.util.zip.  CRC32  
implements Checksum

gp  CRC32()
Erzeugt ein neues CRC32-Objekt mit der Start-Prüfsumme 0.
gp  long getValue()
Liefert den CRC32-Wert.
gp  void reset()
Setzt die interne Prüfsumme auf 0.
gp  void update( byte b[] )
Aktualisiert die Prüfsumme mit dem Feld, durch Aufruf von update(b, 0, b.length).
gp  void update( int b )
Implementiert update() aus Checksum für ein Byte. Nativ implementiert.
gp  void update( byte b[], int off, int len )
Implementiert update() aus Checksum für ein Feld. Nativ implementiert.

CRC eines Datenstroms berechnen

Stellt sich die Aufgabe, die CRC32 eines Datenstroms zu berechnen, so wäre eine Möglichkeit, einen Datenstrom entgegenzunehmen und anschließend so lange Bytefolgen ausgelesen, bis available() null liefert. Immer dann lässt sich mit update() die Püfsumme korrigieren. Bei großen Dateien ist es sicherlich angebracht, Blöcke einzulesen, die dann mit der crc.update(byte[])-Methode verarbeitet werden.

Neben dieser selbstprogrammieren Möglichkeit, lässt sich auch ein passender Filter nutzen: CheckedInputStream und CheckedOutputStream. Beide sind Filter, die also existierende andere Streams ummanteln und gleichzeitig die Berechnung erledigen.

Listing 12.31   CRC32Demo.java


import java.io.*;
import java.util.zip.*;

class CRC32Demo
{
  static public void main( String args[] ) throws IOException
  {
    InputStream in = CRC32Demo.class.getResourceAsStream( "CRC32Demo.java" );

    CRC32 crc = new CRC32();

    CheckedInputStream cis = new CheckedInputStream( in, crc );

    while ( cis.read() !=1 )
      ;

    in.close();

    System.out.println( Long.toHexString( crc.getValue()) );
  }
}

Galileo Computing

12.13.3 Die Adler32-Klasse  toptop

Diese Klasse ist eine weitere Klasse, mit der sich eine Prüfsumme berechnen lässt. Doch warum zwei Verfahren? Ganz einfach. Die Berechnung von CRC32-Prüfsummen kostet – obwohl in C(++) programmiert – viel Zeit. Die Adler32-Prüfsumme lässt sich wesentlich schneller berechnen und bietet ebenso eine geringe Wahrscheinlichkeit, dass Fehler unentdeckt bleiben. Der Algorithmus ist nach seinem Programmierer Mark Adler benannt und ist eine Erweiterung des Fletcher-Algorithmus, definiert im ITU-T X.224/ISO 8073 Standard, auf 32-Bit-Zahlen. Die Adler32-Prüfsumme setzt sich aus zwei Summen für ein Byte zusammen. s1 ist die Summe aller Bytes und s2 die Summe aller s1. Beide Werte werden Modulo 65521 genommen. Am Anfang ist s1 = 1 und s2 = 0. Die Adler32-Prüfsumme speichert den Wert als s2 * 65536 + s1 in der MSB (Most-Significant-Byte First, Netzwerkreihenfolge).

Eine Beschreibung der Kompression und des Adler32-Algorithmus findet sich im Internet-Draft »ZLIB Compressed Data Format Specification version 3.3«.



class java.util.zip.  Adler32  
implements Checksum

gp  Adler32()
Erzeugt ein neues Adler32-Objekt mit der Start-Prüfsumme 1.
gp  long getValue()
Liefert den Adler32-Wert.
gp  void reset()
Setzt die interne Prüfsumme auf 1.

Die update()-Methoden werden aus dem Interface implementiert.






1   Fletcher, J. G., »An Arithmetic Checksum for Serial Transmissions«. IEEE Transactions on Communications, Ausgabe. COM-30, Nummer. 1, Januar 1982, Seite 247–252.





Copyright © Galileo Press GmbH 2004
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press GmbH, Gartenstraße 24, 53229 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de