Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.
 
Inhaltsverzeichnis
Vorwort
1 Neues in Java 8 und Java 7
2 Fortgeschrittene String-Verarbeitung
3 Threads und nebenläufige Programmierung
4 Datenstrukturen und Algorithmen
5 Raum und Zeit
6 Dateien, Verzeichnisse und Dateizugriffe
7 Datenströme
8 Die eXtensible Markup Language (XML)
9 Dateiformate
10 Grafische Oberflächen mit Swing
11 Grafikprogrammierung
12 JavaFX
13 Netzwerkprogrammierung
14 Verteilte Programmierung mit RMI
15 RESTful und SOAP-Web-Services
16 Technologien für die Infrastruktur
17 Typen, Reflection und Annotationen
18 Dynamische Übersetzung und Skriptsprachen
19 Logging und Monitoring
20 Sicherheitskonzepte
21 Datenbankmanagement mit JDBC
22 Java Native Interface (JNI)
23 Dienstprogramme für die Java-Umgebung
Stichwortverzeichnis

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Java SE 8 Standard-Bibliothek von Christian Ullenboom
Das Handbuch für Java-Entwickler
Buch: Java SE 8 Standard-Bibliothek

Java SE 8 Standard-Bibliothek
Pfeil 9 Dateiformate
Pfeil 9.1 Einfache Dateiformate für strukturierte Daten
Pfeil 9.1.1 Property-Dateien mit java.util.Properties lesen und schreiben
Pfeil 9.1.2 CSV-Dateien
Pfeil 9.1.3 JSON-Serialisierung mit Jackson
Pfeil 9.2 Dokumentenformate
Pfeil 9.2.1 (X)HTML
Pfeil 9.2.2 PDF-Dokumente
Pfeil 9.2.3 Microsoft Office-Dokumente
Pfeil 9.2.4 OASIS Open Document Format
Pfeil 9.3 Datenkompression *
Pfeil 9.3.1 Java-Unterstützung beim Komprimieren
Pfeil 9.3.2 Daten packen und entpacken
Pfeil 9.3.3 Datenströme komprimieren
Pfeil 9.3.4 ZIP-Archive
Pfeil 9.3.5 JAR-Archive
Pfeil 9.4 Bildformate
Pfeil 9.5 Audiodateien
Pfeil 9.5.1 Die Arbeit mit Applets AudioClip
Pfeil 9.5.2 AudioClip von JavaFX
Pfeil 9.5.3 MIDI-Dateien abspielen
Pfeil 9.5.4 ID-Tags aus mp3-Dateien
 
Zum Seitenanfang

9.3Datenkompression * Zur vorigen ÜberschriftZur nächsten Überschrift

Damit Daten weniger Platz auf dem Datenträger einnehmen, werden sie komprimiert. Bei Netzwerkverbindungen ist die logische Konsequenz, dass weniger Daten natürlich auch schneller übertragen werden. Über alle Plattformen hinweg haben sich Standards gebildet. Zwei Kompressionsstandards sollen an dieser Stelle beschrieben werden.

compress/uncompress, gzip/gunzip

Seitdem der LZW-Algorithmus im Juni 1984 im IEEE-Journal beschrieben wurde, gibt es in jedem Unix-System die Dienstprogramme compress und uncompress, die verlustfrei Daten zusammenpacken und wieder auspacken.[ 91 ](Interessanterweise wurde danach der LZW-Algorithmus von der Sperry Company patentiert – dies zeigt eigentlich, wie unsinnig das Patentrecht in den USA ist.)gzip und gunzip[ 92 ](Gibt es sogar für den C64: http://www.cs.tut.fi/~albert/Dev/gunzip/) sind freie Unix-Tools von compress/uncompress und unterliegen der GNU Public License. Das Format enthält eine zyklische Überprüfung bezüglich defekter Daten. Die Endung einer Datei, die mit gzip gepackt ist, wird mit .gz angegeben, wobei die Endung unter compress nur .Z ist. gzip behält die Rechte und Zeitattribute der Dateien bei.

ZIP

Das Dienstprogramm zip bündelt in einem Archiv mehrere Dateien und kann die hierarchische Struktur der Ordner erhalten. Auf jede Datei im ZIP-Archiv lässt sich anschließend individuell zugreifen. Programme wie 7-Zip können unter Windows ZIP-Dateien verarbeiten. Obwohl zip und gzip von der Anwendung her unterschiedlich arbeiten – gzip stellt einen Filter dar, der einen Datenstrom komprimiert –, verwenden sie denselben Algorithmus. Beide basieren auf Algorithmen, die im RFC 1952 definiert sind.

Es gibt auch unkomprimierte ZIP-Archive (allerdings selten). Ein Beispiel dafür waren die Java-Archive des frühen Internet Explorers. Die größte Datei war unkomprimiert 5,3 MB groß, gepackt wäre sie 2 MB leicht. Sie wurde aus Gründen der Geschwindigkeit nicht gepackt, da sich die Daten aus unkomprimierten Archiven schneller lesen lassen, weil keine Prozessorleistung für das Entpacken aufzuwenden ist.

Das Archivformat und Archivierungsprogramm tar

Das unter Unix-Systemen bekannte Dienstprogramm tar[ 93 ](»tar« steht für tape archiver, was übersetzt Bandarchivierer heißt.) bündelt mehrere Dateien zu einer neuen Datei, ohne sie zu komprimieren. Das Ergebnis, ein TAR-Archiv, wird oft anschließend mit dem Tool gzip bzw. bzip2 gepackt. Die Endung ist dann .tar.Z. Werden mehrere Daten erst in einem TAR-Archiv zusammengefasst und dann gepackt, ist die Kompressionsrate höher, als wenn jede Datei einzeln komprimiert wird. Der Grund ist simpel: Das Kompressionsprogramm kann die Redundanz besser ausnutzen. Der Nachteil ist freilich, dass für eine Datei gleich das ganze TAR-Archiv ausgepackt werden muss.

 
Zum Seitenanfang

9.3.1Java-Unterstützung beim Komprimieren Zur vorigen ÜberschriftZur nächsten Überschrift

Unter Java ist ein Paket java.util.zip eingerichtet, um mit komprimierten Dateien zu operieren. Das Paket bietet zur Komprimierung zwei allgemein gebräuchliche Formate: gzip/gunzip zum Komprimieren bzw. Dekomprimieren von Datenströmen und ZIP zum Behandeln von Archiven und zum Komprimieren von Dateien. Auch wird das eigene Archiv-Format JAR (Java Archive) durch das Paket java.util.jar unterstützt. JAR ist eine Erweiterung des ZIP-Formats. Speziell Klassendateien (.class-Dateien) in Java-Archiven können durch java.util.jar.Pack200 noch höher komprimiert werden.

Ingesamt finden sich in der Java-Standard-API Klassen zum

  • Packen/Entpacken von Bytefeldern,

  • Behandeln von ZIP-/JAR-Archiven und zum

  • (De-)Komprimieren von Datenströmen.

Für JAR und das Pack200-Format gibt es im bin-Verzeichnis vom JDK auch entsprechende Kommandozeilenwerkzeuge, namentlich jar, pack200 und unpack200.

Unterstützung von tar und bzip2 von Drittanbietern

TAR-Archive werden nicht unterstützt, doch gibt es eine Reihe freier Implementierungen, unter anderem von der Apache Software Foundation: http://tutego.de/go/tarcvs; sie definieren Ein- und Ausgabeströme. Für bzip2 bietet die Apache Foundation Unterstützung über das Paket Commons Compress (http://tutego.de/go/bzip2). Neben der Unterstützung durch das Paket java.util.zip für bzip2-Ströme und ZIP-Dateien ist TrueZIP (http://truezip.java.net/) eine sehr interessante Open-Source-Bibliothek, die die Archivarbeit stark vereinfacht, etwa erlaubt, Einträge in ZIP-Dateien hinzuzufügen. Mit NIO.2 lässt sich auf ZIP-Archiven wie auf einem Dateisystem arbeiten, doch implementiert TrueZip neben ZIP noch weitere Containerformate, für die das JDK aktuell keine Unterstützung mitbringt. TrueZIP integriert sich nahtlos als FileSystem-Provider in Java 7.

[zB]Beispiel

Lies mit TrueZIP eine Datei aus einem komprimierten Archiv aus dem Internet:[ 94 ](http://truezip.java.net/truezip-path/index.html)

String url = "http://acme.com/download/everything.tar.gz/README.TXT";
Path path = new TPath( new URI( url ) );
try ( InputStream in = Files.newInputStream(path) ) {
// Archiv-Eintrag lesen
}
 
Zum Seitenanfang

9.3.2Daten packen und entpacken Zur vorigen ÜberschriftZur nächsten Überschrift

Im Mittelpunkt der Kompression/Dekompression stehen die Klassen java.util.zip.Deflater (komprimieren) und java.util.zip.Inflater (entpacken). Dort sind die zentralen Methoden deflate(…) und inflate(…) zu finden. Ein Beispiel zeigt die Nutzung anschaulich:

Listing 9.3com/tutego/insel/io/zip/InflaterDeflaterDemo.java, main()

byte[] input = "aaaaaaaaaaaaaaaa".getBytes();

System.out.printf( "%X%n", new BigInteger( 1, input ) );

// Komprimieren

byte[] output = new byte[100];
Deflater compresser = new Deflater( Deflater.BEST_COMPRESSION );
compresser.setInput( input );
compresser.finish();
int compressedBytes = compresser.deflate( output );

System.out.printf( "%X%n", new BigInteger( 1, Arrays.copyOf( output, compressedBytes ) ) );

// Dekomprimieren

Inflater decompresser = new Inflater();
decompresser.setInput( output, 0, compressedBytes );
byte[] result = new byte[100];
int uncompressedBytes = decompresser.inflate( result );
decompresser.end();

System.out.printf( "%X%n", new BigInteger( 1, Arrays.copyOf( result, uncompressedBytes ) ) );

Dem Deflater kann im Konstruktor eine Kompressionsqualität mitgegeben werden; ohne Angabe ist das DEFAULT_COMPRESSION. Als Nächstes werden dem Deflater die zu komprimierenden Daten übergeben – das übernimmt setInput(…), eine Methode, die es auch überladen gibt, um nur einen Ausschnitt eines Arrays beachten zu können. Die finish()-Methode signalisiert, dass die Kompression mit den gegebenen Daten endet. deflate(…) startet die eigentliche Kompression und schreibt das Ergebnis in das übergebene Byte-Array. Die Rückgabe der Methode sagt etwas über die komprimierten Bytes aus. Die Feldgröße muss für das komprimierte Ergebnis groß genug sein, andernfalls wird das Ergebnis einfach abgeschnitten, und die Rückgabe ist gleich der Feldgröße, was wenig nützlich ist.

Das Entpacken ist im Prinzip genauso zu verstehen. Dem Inflater ist nicht die Kompressionsqualität zu übergeben, die steckt im komprimierten Feld selbst. Die Eingabe setzt setInput(…), wobei auch diese Methode wieder überladen ist. Da wir hier nur einen Teil des Puffers betrachten, ist die Methode mit dem Feld, Start- und Endwert genau richtig. Abschließend packt inflate(…) aus und setzt das unkomprimierte Ergebnis in das Feld, das der Methode übergeben wurde. Die Rückgabe ist die Anzahl entpackter Bytes. end() gibt Ressourcen frei. Damit folgt die Ausgabe:

61616161616161616161616161616161
78DA4B4C44050033980611
61616161616161616161616161616161

Die Klassen Deflater und Inflater sind einfach gestrickt und behandeln nur Arrays, sind aber keine Datenströme (InputStream/OutputStream), mit denen Entwickler oft Daten verarbeiten. Daher bietet die Java-Bibliothek spezielle Stream-Klassen, die im Hintergrund mit den Deflater/Inflater-Klassen arbeiten.

 
Zum Seitenanfang

9.3.3Datenströme komprimieren Zur vorigen ÜberschriftZur nächsten Überschrift

Zum Packen und Entpacken von Strömen wollen wir uns im Folgenden das populäre gzip-Kompressionsformat und die Datenströme java.util.zip.GZIPInputStream (ein spezieller FilterInputStream) und java.util.zip.GZIPOutputStream (ein FilterOutputStream) genauer anschauen.

UML-Diagramm mit den GZIPXXXStream-Klassen

Abbildung 9.1UML-Diagramm mit den GZIPXXXStream-Klassen

Daten packen

Das Paket java.util.zip bietet zwei Unterklassen von DeflaterOutputStream (eine Unterklasse von FilterOutputStream), die das Schreiben komprimierter Daten ermöglichen: GZIPOutputStream und ZipOutputStream. Um Daten unter dem gzip-Algorithmus zu packen, müssen wir einfach einen vorhandenen Datenstrom zu einem GZIPOutputStream erweitern. Die Klasse ZipOutputStream dient ZIP-Archiven, denen wir uns später widmen werden.

OutputStream fos = Files.newOutputStream( path );
OutputStream zipout = new GZIPOutputStream( fos );
Klassendiagramm mit Methoden aus GZIPOutputStream und ihrer Oberklasse

Abbildung 9.2Klassendiagramm mit Methoden aus GZIPOutputStream und ihrer Oberklasse

class java.util.zip.GZIPOutputStream
extends DeflaterOutputStream
  • GZIPOutputStream(OutputStream out)
    Erzeugt einen packenden Datenstrom mit der voreingestellten Puffergröße von 512 Byte.

  • GZIPOutputStream(OutputStream out, int size)
    Erzeugt einen packenden Datenstrom mit einem Puffer der Größe size.

gzip-Kommandozeilenprogramm

Das folgende Programm soll eine Datei nach dem gzip-Format packen. Es verhält sich in der Arbeitsweise ähnlich wie das unter Unix bekannte Programm gzip:

Listing 9.4com/tutego/insel/io/zip/gzip.java

package com.tutego.insel.io.zip;

import java.io.*;
import java.nio.file.*;
import java.util.zip.GZIPOutputStream;

public class gzip {

public static void main( String[] args ) {
if ( args.length != 1 ) {
System.err.println( "Benutzung: gzip <source>" );
return;
}

Path gzPath = Paths.get( args[ 0 ] + ".gz" );
try ( OutputStream gos = new GZIPOutputStream( Files.newOutputStream( gzPath ) ) ) {
Files.copy( Paths.get( args[ 0 ] ), gos );
}
catch ( IOException e ) {
System.err.println( "Fehler: Kann nicht packen " + args[ 0 ] );
}
}
}

Das Programm prüft zuerst, ob ein Argument auf der Kommandozeile vorhanden ist. Aus diesem Argument konstruiert es einen Pfad mit der Endung .gz. Den OutputStream dekoriert anschließend der GZIPOutputStream. Mit Files.copy(…) bekommen wir automatisch den Pfad geöffnet, alle Bytes ausgelesen und in den Ausgabestrom kopiert. Wir müssen also nicht von Hand aus dem Eingabestrom Block für Block per read(…) auslesen und per write(…) in den Ausgabestrom übertragen, sondern diese Funktionalität steckt schon in der copy(…)-Methode.

Daten entpacken

Um die Daten zu entpacken, müssen wir nur den umgekehrten Weg beschreiten. Zum Einsatz kommt hier eine der beiden Unterklassen von DeflaterInputStream (einer direkten Unterklasse von FilterInputStream). Wieder wickeln wir einen GZIPInputStream um einen InputStream und lesen dann daraus.

class java.util.zip.GZIPInputStream
extends InflaterInputStream
  • GZIPInputStream(InputStream in, int size)
    Erzeugt einen auspackenden Datenstrom mit einem Puffer der Größe size.

  • GZIPInputStream(InputStream in)
    Erzeugt einen auspackenden Datenstrom mit der voreingestellten Puffergröße von 512 Byte.

gunzip-Kommandozeilenprogramm

Zum Java-Programm gzip wollen wir eine zweite Anwendung hinzunehmen, die sich so verhält, wie das unter Unix bekannte Kommandozeilenprogramm gunzip:

Listing 9.5com/tutego/insel/io/zip/gunzip.java

package com.tutego.insel.io.zip;

import java.io.*;
import java.nio.file.*;
import java.util.zip.GZIPInputStream;

public class gunzip {

public static void main( String[] args ) {
if ( args.length != 1 ) {
System.err.println( "Benutzung: gunzip <source>" );
return;
}

String filename = args[ 0 ];
Path srcPath, destPath;

if ( filename.toLowerCase().endsWith( ".gz" ) ) {
srcPath = Paths.get( filename );
destPath = Paths.get( filename.replaceAll( "\\.gz$", "" ) );
}
else {
srcPath = Paths.get( filename + ".gz" );
destPath = Paths.get( filename );
}

try ( InputStream is = new GZIPInputStream( Files.newInputStream( srcPath ) ) ) {
Files.copy( is, destPath );
}
catch ( IOException e ) {
System.err.println( "Fehler: Kann nicht entpacken " + filename );
}
}
}

Endet die Datei auf .gz, so entwickeln wir daraus den herkömmlichen Dateinamen. Endet sie nicht auf dieses Suffix, so nehmen wir einfach an, dass die gepackte Datei diese Endung besitzt, der Benutzer diese aber nicht angegeben hat. Nach dem Zusammensetzen des Dateinamens holen wir von der gepackten Datei einen InputStream und packen einen GZIPInputStream darum. Das Kopieren der Bytes aus dem entpackenden Eingabestrom in die Ausgabe übernimmt die praktische Files.copy(…)-Methode.

 
Zum Seitenanfang

9.3.4ZIP-Archive Zur vorigen ÜberschriftZur nächsten Überschrift

Der Zugriff auf die Daten eines ZIP-Archivs unterscheidet sich schon deshalb vom Zugriff auf die Daten eines gzip-Streams, weil diese in Form eines Archivs vorliegen. Unter ZIP wird jede eingebettete Datei einzeln und unabhängig komprimiert. Wurden etwa über TAR vorher alle Dateien in ein unkomprimiertes Archiv übernommen, kann der Packalgorithmus gzip beim Packen dieser Dateisammlung bessere Ergebnisse erzielen, als wenn – wie beim ZIP-Verfahren – alle Dateien einzeln gepackt würden.

Das ursprüngliche ZIP-Format behandelt nur Dateien bis 4 GB. Diese Beschränkung behebt ZIP64, was Java ebenfalls ab der Version 7 unterstützt.

Die Klassen ZipFile und ZipEntry

Objekte der Klasse ZipFile repräsentieren ein ZIP-Archiv. Die Einträge im ZIP-Archiv sind Dateien und Ordner, die Java durch die Klasse ZipEntry darstellt. Liegt einmal ein ZipEntry-Objekt vor, können ihm durch verschiedene Methoden Dateiattribute entlockt werden, beispielsweise die Originalgröße, das Kompressionsverhältnis, das Datum, wann die Datei angelegt wurde und weitere Informationen. Auch kann ein Datenstrom erzeugt werden, sodass sich eine komprimierte Datei im Archiv lesen und schreiben lässt.

Um auf die Dateien eines Archivs zuzugreifen, muss zunächst ein ZipFile-Objekt erzeugt werden:

class java.util.zip.ZipFile
  • ZipFile(String name) throws ZipException, IOException

  • ZipFile(File file) throws ZipException, IOException
    Öffnet ein ZIP-Archiv zum Lesen über den Dateinamen oder das File-Objekt.

  • ZipFile(File file, int mode) throws ZipException, IOException
    Öffnet ein ZIP-Archiv mit dem gegebenen File-Objekt. Der Modus ZipFile.OPEN_READ oder ZipFile.OPEN_READ|ZipFile.OPEN_DELETE bestimmt den Zugriff auf das Archiv.

Eine ZipException ist eine Unterklasse von IOException.

Die im ZIP-Archiv abgelegten Dateien oder Verzeichnisse, also die ZipEntry-Einträge, können auf zwei Arten ermittelt werden:

  • Die Methode entries() von ZipFile liefert eine Aufzählung von ZipEntry-Einträgen. Genauer gesagt ist der Rückgabetyp Enumeration<? extends ZipEntry>.

  • Ist der Name der komprimierten Datei oder des Ordners bekannt, liefert getEntry(String) sofort ein ZipEntry-Objekt.

[zB]Beispiel

Iteriere durch die Einträge eines Archivs, und gib die Namen aus:

ZipFile zf = new ZipFile( "foo.zip" );
for ( Enumeration<? extends ZipEntry> e = zf.entries();
e.hasMoreElements(); )
{
ZipEntry entry = e.nextElement();
System.out.println( entry.getName() );
}

Mit Collections.list(Enumeration<T> e) lässt sich die Schleife mit einem erweiterten for verkürzen. Die folgenden Beispiele nutzen diese Möglichkeit.

class java.util.zip.ZipFile
  • ZipEntry getEntry(String name)
    Liefert eine Datei aus dem Archiv. Liefert null, wenn kein Eintrag mit dem Namen existiert.

  • Enumeration<? extends ZipEntry> entries()
    Gibt eine Aufzählung des ZIP-Archivs in Form von ZipEntry-Objekten zurück.

  • Stream<? extends ZipEntry> stream()
    Liefert einen Stream mit ZipEntry-Objekt. Neu in Java 8.

  • String getName()
    Liefert den Pfadnamen des ZIP-Archivs.

  • int size()
    Gibt die Anzahl der Einträge im ZIP-Archiv zurück.

  • void close() throws IOException
    Schließt das ZIP-Archiv.

Eine IllegalStateException ist bei getEntry(String) und entries() die Folge, wenn das ZIP-Archiv schon geschlossen wurde.

ZipEntry und die Datei-Attribute

Ein ZipEntry-Objekt repräsentiert eine Datei oder ein Verzeichnis eines Archivs. Diese Datei kann gepackt (dafür ist die Konstante ZipEntry.DEFLATED reserviert) oder auch ungepackt sein (angezeigt durch die Konstante ZipEntry.STORED). Auf dem Objekt können verschiedene Attribute gesetzt und abgefragt werden. Dadurch lassen sich Statistiken über Kompressionsraten und Weiteres ermitteln:

Listing 9.6com/tutego/insel/io/zip/ZipListDemo.java, main()

try ( ZipFile zipFile = new ZipFile( "c:/a/b.zip" ) ) {
for ( ZipEntry entry : Collections.list( zipFile.entries() ) )
System.out.printf( "%s%-54s Größe: %6d Gepackt: %6d %tc%n",
entry.isDirectory() ? "+" : " ",
entry.getName(),
entry.getSize(),
entry.getCompressedSize(),
entry.getTime() );
}

Die Ausgabe könnte zum Beispiel sein:

+a/ Größe: 0 Gepackt: 0 Do Mai 24 10:13:46 CEST 2007
a/a.html Größe: 42924 Gepackt: 6962 Do Mai 24 10:03:20 CEST 2007
a/links.xml Größe: 18900 Gepackt: 1406 Do Mai 24 10:03:20 CEST 2007
class java.util.zip.ZipEntry
implements Cloneable
  • String getName()
    Liefert den Namen des Eintrags.

  • void setTime(long time)
    Ändert die Modifikationszeit des Eintrags.

  • long getTime()
    Liefert die Modifikationszeit des Eintrags oder –1, wenn diese nicht angegeben ist.

  • void setSize(long size)
    Setzt die Größe der unkomprimierten Datei. Wir werden mit einer IllegalArgumentException bestraft, wenn die Größe kleiner 0 oder größer 0xFFFFFFFF ist.

  • long getSize()
    Liefert die Größe der unkomprimierten Datei oder –1, falls diese unbekannt ist.

  • long getCrc()
    Liefert die CRC-32-Checksumme der unkomprimierten Datei oder –1, falls diese unbekannt ist.

  • void setMethod(int method)
    Setzt die Kompressionsmethode entweder auf STORED oder auf DEFLATED.

  • int getMethod()
    Liefert die Kompressionsmethode. Die Rückgabe ist entweder STORED, DEFLATED oder –1, falls unbekannt.

  • void setExtra(byte[] extra)
    Setzt das optionale Zusatzfeld für den Eintrag. Übersteigt die Größe des Zusatzfeldes 0xFFFF Byte, dann wird eine IllegalArgumentException ausgelöst.

  • byte[] getExtra()
    Liefert das Extrafeld oder null, falls es nicht belegt ist.

  • void setComment(String comment)
    Setzt einen Kommentar-String, der 0xFFFF Zeichen lang sein darf (sonst wird eine IllegalArgumentException ausgelöst).

  • String getComment()
    Gibt den Kommentar oder null zurück.

  • long getCompressedSize()
    Liefert die Dateigröße nach dem Komprimieren oder –1, falls diese unbekannt ist. Ist der Kompressionstyp ZipEntry.STORED, dann stimmt diese Größe natürlich mit dem Rückgabewert von getSize() überein.

  • boolean isDirectory()
    Liefert true, falls der Eintrag ein Verzeichnis ist. Der Name der Datei endet mit einem Slash (/).

Seit Java 8 lässt sich auch der Zeitstempel eines ZipEntry auslesen und ändern. Die neuen Methoden sind:

  • ZipEntry setCreationTime(FileTime time)

  • FileTime getCreationTime()

  • ZipEntry setLastModifiedTime(FileTime time)

  • FileTime getLastModifiedTime()

  • ZipEntry setLastAccessTime(FileTime time)

  • FileTime getLastAccessTime()

Der Typ java.nio.file.attribute.FileTime repräsentiert Dateizeiten und fällt etwas aus dem Rahmen, da hier java.util.zip mit java.nio gemischt wird, aber so ist das heutzutage, wo sich APIs weiterentwickeln.

Auch überschreibt ZipEntry die Methoden toString() (entspricht getName()), hashCode() (entspricht getName().hashCode()) und clone() aus Object, equals(Object) aber merkwürdigerweise nicht; eine Hashcode-Implementierung ohne Gleichheitstest ist quasi wertlos.

Dateien auspacken

Um Dateien auszupacken, bietet die Java-Bibliothek zwei Möglichkeiten. Die erste ist, mittels getInputStream(ZipEntry) ein InputStream-Objekt zu holen und dann auf den Inhalt der Datei zuzugreifen (es ist bemerkenswert, dass getInputStream(ZipEntry) keine Methode von ZipEntry ist, sondern von ZipFile). Die andere Variante arbeitet über ZipInputStream, einen Weg, den wir hier nicht weiter beschreiben.

[zB]Beispiel

Liegt im Archiv moers.zip die gepackte Datei DerAlteSack.png, dann gelangen wir mit folgenden Zeilen an deren entpackten Inhalt:

ZipFile zipFile = new ZipFile( "moers.zip" );
ZipEntry entry = zipFile.getEntry( "DerAlteSack.png" );
InputStream is = zipFile.getInputStream( entry );
class java.util.zip.ZipFile
  • InputStream getInputStream(ZipEntry entry) throws IOException
    Gibt einen Eingabestrom zurück, mit dem auf den Inhalt einer Datei zugegriffen werden kann. Es folgt eine IllegalStateException, wenn das ZIP-Archiv schon geschlossen wurde.

Ein Archiv Datei für Datei entpacken

Damit ein Java-Programm das gesamte ZIP-Archiv entpackt, lässt sich mit der Aufzählung von entries() durch das Archiv laufen und für jeden Eintrag eine Datei oder ein Verzeichnis erzeugen. Das Speichern soll eine eigene Methode extractEntry(ZipFile, ZipEntry, String) übernehmen, die zunächst erkennt, ob es sich bei der Datei im ZIP-Archiv um ein Verzeichnis handelt oder nicht:

  • Liefert das ZipEntry-Objekt bei isDirectory() ein true, dann legen wir nur Ordner mittels Files.createDirectories() an und keine Datei.

  • Steht das ZipEntry für eine Datei, dann kann diese in einem Unterordner stehen, und es müssen ebenfalls die nötigen Ordner angelegt werden. Nachdem für ein Ziel ein OutputStream angelegt wurde, lassen sich alle ZipFile-Bytes von getInputStream(ZipEntry) kopieren.

So sieht das fertige Programm aus:

Listing 9.7com/tutego/insel/io/zip/unzip.java

package com.tutego.insel.io.zip;

import java.io.*;
import java.nio.file.*;
import java.util.Collections;
import java.util.zip.*;

public class unzip {

public static void main( String[] args ) {
if ( args.length != 2 )
System.out.println( "Benutzung: unzip <zipfile> <destination>" );
else {
try ( ZipFile zipFile = new ZipFile( args[ 0 ] ) ) {
for ( ZipEntry entry : Collections.list( zipFile.entries() ) ) {
System.out.print( entry.getName() + "." );
extractEntry( zipFile, entry, args[ 1 ] );
System.out.println( ".. entpackt" );
}
}
catch ( FileNotFoundException e ) {
System.err.println( "Fehler: Zip-Datei nicht gefunden!" );
}
catch ( IOException e ) {
System.err.println( "Fehler: Allgemeiner Ein-/Ausgabefehler!" );
}
}
}

private static void extractEntry( ZipFile zipFile, ZipEntry entry, String destDir )
throws IOException {
Path destPath = Paths.get( destDir, entry.getName() );

if ( entry.isDirectory() )
Files.createDirectories( destPath );
else {
Files.createDirectories( destPath.getParent() );

try ( InputStream is = zipFile.getInputStream( entry ) ) {
Files.copy( is, destPath );
}
}
}
}

ZIP-Archiv aufbauen und Dateien hinzufügen

Das Hinzufügen von Dateien zu einem neuen ZIP-Archiv unterscheidet sich ein wenig vom Lesen der Dateien, da hier die Klasse ZipFile nicht benötigt wird. Im Mittelpunkt steht die Klasse ZipOutputStream mit zwei Schritten:

  1. Ein ZipOutputStream wird aufgebaut, etwa über new ZipOutputStream(Files.newOutputStream(zipfilePath)).

  2. new ZipEntry(String) oder new ZipEntry(ZipEntry) erzeugt einen Archiv-Eintrag, und putNextEntry(ZipEntry) verbindet diesen mit dem ZipOutputStream. Nach dem Schreiben schließt closeEntry() das Hinzufügen ab.

Erzeugt ZipOutputStream eine Datei, lässt sich die Kompressionsrate über die Methode setLevel(int) einstellen. Der Level ist eine Zahl zwischen 0 und 9. Die Kompression übernimmt ein Deflater-Objekt, das im DeflaterOutputStream (das ist die Oberklasse von ZipOutputStream) verwaltet wird. So ruft ZipOutputStream lediglich vom Deflater die Methode setLevel(int) auf.

[»]Hinweis

ZIP-Archive können über ZipOutputStream nur neu angelegt, aber nicht erweitert werden. Sollen Dateien/Verzeichnisse hinzukommen, müssen alte Elemente in das neue ZIP kopiert werden. NIO.2 und ein ZIP-Provider lösen allerdings das Problem sowie die quelloffene Bibliothek TrueZIP.

 
Zum Seitenanfang

9.3.5JAR-Archive Zur vorigen ÜberschriftZur nächsten Überschrift

JAR-Archive sind mit ZIP-Archiven vergleichbar, mit dem Unterschied, dass sie eine Manifest-Datei beinhalten. Die Arbeitsweise und der Zugriff auf die Einträge sind daher denen der ZIP-Dateien sehr ähnlich. Die Klasse java.util.jar.JarFile repräsentiert ein JAR-Archiv, und ein java.util.jar.JarEntry ist ein Eintrag in dem Archiv. JarFile ist eine Unterklasse von ZipFile, und JarEntry ist eine Unterklasse von ZipEntry.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java SE 8 Standard-Bibliothek Java SE 8 Standard-Bibliothek
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Java ist auch eine Insel
Java ist auch eine Insel


Zum Rheinwerk-Shop: Professionell entwickeln mit Java EE 8
Professionell entwickeln mit Java EE 8


Zum Rheinwerk-Shop: Besser coden
Besser coden


Zum Rheinwerk-Shop: Entwurfsmuster
Entwurfsmuster


Zum Rheinwerk-Shop: IT-Projektmanagement
IT-Projektmanagement


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2018
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.

 
Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern