Java-Tipp 49: So extrahieren Sie Java-Ressourcen aus JAR- und Zip-Archiven

Die meisten Java-Programmierer sind sich der Vorteile der Verwendung einer JAR-Datei zum Bündeln aller verschiedenen Ressourcen (dh Klassendateien, Sounds und Bilder), aus denen ihre Java-Lösung besteht, ziemlich klar. (Wenn Sie mit JAR-Dateien nicht vertraut sind, lesen Sie den Abschnitt Ressourcen unten.) Eine häufig gestellte Frage von Personen, die gerade erst damit beginnen, JAR-Dateien in ihre Trickkiste aufzunehmen, lautet: "Wie extrahiere ich ein Bild aus einem KRUG?" Wir werden diese Frage beantworten und eine Klasse bereitstellen, um das Extrahieren einer Ressource aus einem JAR zu vereinfachen!

Laden eines GIF-Bildes

Angenommen, wir haben eine JAR-Datei mit einer Reihe von GIF-Bilddateien, die wir in unserer Anwendung verwenden möchten. So können wir mit den JarResources von der JAR aus auf eine Bilddatei zugreifen:

JarResources jar = neue JarResources ("Images.jar"); Image logo = Toolkit.getDefaultToolkit (). CreateImage (jar.getResource ("logo.gif");

Dieses Code-Snippet zeigt, dass wir ein JarResourcesObjekt erstellen können, das in der JAR-Datei initialisiert ist und die Ressource enthält, die wir verwenden möchten - Images.jar. Anschließend verwenden wir die JarResources'getResource()Methode, um die Rohdaten aus der Datei logo.gif für die createImage()Methode des AWT-Toolkits bereitzustellen .

Ein Hinweis zur Benennung

Die JarResource ist ein recht einfaches Beispiel für die Verwendung verschiedener von Java 1.1 bereitgestellter Funktionen zum Bearbeiten von JAR- und Zip-Archivdateien.

Ein kurzer Hinweis zur Benennung. Die Archivierungsunterstützung in Java begann tatsächlich mit dem beliebten Zip-Archivierungsformat (siehe "Java-Tipp 21: Verwenden Sie Archivdateien, um das Laden von Applets zu beschleunigen"). Bei der Implementierung der Java-Unterstützung zur Bearbeitung der Archivdateien wurden ursprünglich alle Klassen und so weiter im Paket java.util.zip abgelegt. Diese Klassen beginnen normalerweise mit " Zip." Aber irgendwo auf dem Weg zu Java 1.1 werden die Kräfte, die geändert werden, den Namen des Archivs ändern, um mehr auf Java ausgerichtet zu sein. Daher sind die heutigen JAR-Dateien im Grunde genommen Zip-Dateien.

Wie es funktioniert

Die wichtigen Datenfelder für die JarResourcesKlasse werden verwendet, um den Inhalt der angegebenen JAR-Datei zu verfolgen und zu speichern:

öffentliche letzte Klasse JarResources {public boolean debugOn = false; private Hashtable htSizes = new Hashtable (); private Hashtable htJarContents = neue Hashtable (); private String jarFileName;

Die Instanziierung der Klasse legt also den Namen der JAR-Datei fest und ruft dann die init()Methode auf, um die gesamte eigentliche Arbeit zu erledigen:

public JarResources (String jarFileName) {this.jarFileName = jarFileName; drin(); }}

Jetzt init()lädt die Methode so ziemlich nur den gesamten Inhalt der angegebenen JAR-Datei in eine Hashtabelle (Zugriff über den Namen der Ressource).

Dies ist eine ziemlich heftige Methode, also lassen Sie es uns etwas weiter aufschlüsseln. Die ZipFileKlasse bietet uns grundlegenden Zugriff auf die Header-Informationen des JAR / Zip-Archivs. Dies ähnelt den Verzeichnisinformationen in einem Dateisystem. Hier listen wir alle Einträge in der auf ZipFileund bauen die Hashtabelle htSizes mit der Größe jeder Ressource im Archiv auf:

private void init () {try {ZipFile zf = new ZipFile (jarFileName); Aufzählung e = zf.entries (); while (e.hasMoreElements ()) {ZipEntry ze = (ZipEntry) e.nextElement (); if (debugOn) {System.out.println (dumpZipEntry (ze)); } htSizes.put (ze.getName (), neue Ganzzahl ((int) ze.getSize ())); } zf.close ();

Als nächstes greifen wir über die ZipInputStreamKlasse auf das Archiv zu . Die ZipInputStreamKlasse macht die ganze Magie, damit wir jede der einzelnen Ressourcen im Archiv lesen können. Wir lesen die genaue Anzahl der Bytes aus dem Archiv, aus dem jede Ressource besteht, und speichern diese Daten in der Hashtabelle htJarContents, auf die über den Ressourcennamen zugegriffen werden kann:

FileInputStream fis = neuer FileInputStream (jarFileName); BufferedInputStream bis = neuer BufferedInputStream (fis); ZipInputStream zis = neuer ZipInputStream (bis); ZipEntry ze = null; while ((ze = zis.getNextEntry ())! = null) {if (ze.isDirectory ()) {continue; } if (debugOn) {System.out.println ("ze.getName () =" + ze.getName () + "," + "getSize () =" + ze.getSize ()); } int size = (int) ze.getSize (); // -1 bedeutet unbekannte Größe. if (size == - 1) {size = ((Integer) htSizes.get (ze.getName ())). intValue (); } Byte [] b = neues Byte [(int) Größe]; int rb = 0; int chunk = 0; während (((int) size - rb)> 0) {chunk = zis.read (b, rb, (int) size - rb); if (chunk == - 1) {break; } rb + = chunk; } // zur internen Ressource hinzufügen Hashtabelle htJarContents.put (ze.getName (), b); if (debugOn) {System.out.println (ze.getName () + "rb =" + rb + ", size =" + size + ", csize =" + ze.getCompressedSize ()); }}} catch (NullPointerException e) {System.out.println ("done."); } catch (FileNotFoundException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); }}

Beachten Sie, dass der Name, der zur Identifizierung jeder Ressource verwendet wird, der qualifizierte Pfadname der Ressource im Archiv ist, nicht beispielsweise der Name einer Klasse in einem Paket, ZipEntrydh die Klasse aus dem Paket java.util.zip Sie müssen "java / util / zip / ZipEntry" und nicht "java.util.zip.ZipEntry" heißen.

Der letzte wichtige Teil des Codes ist der einfache Testtreiber. Der Testtreiber ist eine einfache Anwendung, die einen JAR / Zip-Archivnamen und den Namen einer Ressource verwendet. Es versucht, die Ressource im Archiv zu finden und meldet ihren Erfolg oder Misserfolg:

public static void main (String [] args) löst IOException aus {if (args.length! = 2) {System.err.println ("usage: java JarResources"); System.exit (1); } JarResources jr = neue JarResources (args [0]); Byte [] buff = jr.getResource (args [1]); if (buff == null) {System.out.println ("Konnte nicht finden" + args [1] + "."); } else {System.out.println ("Gefunden" + Argumente [1] + "(Länge =" + Buff.Länge + ")."); }}} // Ende der JarResources-Klasse.

Und da hast du es. Eine einfach zu verwendende Klasse, die all die Unordnung verbirgt, die mit der Verwendung von Ressourcen verbunden ist, die in JAR-Dateien versteckt sind.

Übungen für den Leser

Nachdem Sie nun das Gefühl haben, Ressourcen aus einer Archivdatei zu extrahieren, finden Sie hier einige Anweisungen, die Sie beim Ändern und Erweitern der JarResourcesKlasse untersuchen sollten:

  • Anstatt alles während des Baus zu laden, sollten Sie das Laden verzögern. Bei einer großen JAR-Datei ist möglicherweise nicht genügend Speicher vorhanden, um alle Dateien während der Erstellung zu laden.
  • Anstatt einfach eine generische Zugriffsmethode wie getResource()bereitzustellen, könnten wir auch andere ressourcenspezifische Zugriffsmethoden bereitstellen, z. B. getImage()die ein Java- ImageObjekt zurückgeben, getClass()ein Java- ClassObjekt zurückgeben (mithilfe eines benutzerdefinierten Klassenladeprogramms) und so weiter. Wenn die JAR-Datei klein genug ist, können wir alle Ressourcen basierend auf ihren Erweiterungen (.gif, .class usw.) vorab erstellen.
  • Einige Methoden sollten Informationen über die angegebene JAR-Datei selbst bereitstellen (im Grunde genommen ein Wrapper ZipFile), einschließlich: der Anzahl der Jar / Zip-Einträge; ein Enumerator, der alle Namen von Ressourcen zurückgibt; Accessoren, die die Länge (und andere Attribute) eines bestimmten Eintrags zurückgeben; und ein Accessor, der die Indizierung ermöglicht, um nur einige zu nennen.
  • JarResourceskann erweitert werden, um von Applets verwendet zu werden. Durch die Verwendung von Applet-Parametern und der URLConnectionKlasse kann der JAR-Inhalt aus dem Netzwerk heruntergeladen werden, anstatt die Archive als lokale Dateien zu öffnen. Darüber hinaus können wir diese Klasse als benutzerdefinierten Java-Inhaltshandler erweitern.

Fazit

Wenn Sie wissen wollten, wie man ein Bild aus einer JAR-Datei extrahiert, haben Sie jetzt eine Möglichkeit. Sie können nicht nur Bilder mit einer JAR-Datei verarbeiten, sondern mit der neuen Klasse in diesem Tipp können Sie auch jede Ressource aus einer JAR extrahieren .

Arthur Choi arbeitet derzeit für IBM als beratender Programmierer. Er hat für verschiedene Unternehmen gearbeitet, darunter SamSung Network Laboratory und MITRE. Die verschiedenen Projekte, an denen er gearbeitet hat, sind Client / Server-Systeme, verteiltes Objekt-Computing und Netzwerkmanagement. Er hat eine Reihe von Sprachen in verschiedenen Betriebssystemumgebungen verwendet. Er begann 1981 mit FORTRAN IV und COBOL zu programmieren. Später wechselte er zu C und C ++ und arbeitet seit etwa zwei Jahren mit Java. Er interessiert sich am meisten für Anwendungen von Java in den Bereichen Datenrepositorys über Weitverkehrsnetzwerke und parallele und verteilte Verarbeitung über das Internet (mithilfe von agentenbasierter Programmierung). John Mitchell, ein Mitarbeiter, Berater und Direktor seines eigenen Unternehmens, hat in den letzten zehn Jahren in die Entwicklung modernster Computersoftware investiert.und bei der Beratung und Schulung anderer Entwickler. Er hat Beratung zu Java-Technologie, Compilern, Dolmetschern, webbasierten Anwendungen und Internet-Handel angeboten. John war Co-Autor von Making Sense of Java: Ein Leitfaden für Manager und den Rest von uns und hat Artikel in Programmierzeitschriften veröffentlicht. Zusätzlich zum Schreiben der Spalte Java Tips für JavaWorld moderiert er die Newsgroups comp.lang.tcl.announce und comp.binaries.geos.

Erfahren Sie mehr über dieses Thema

  • Hier ist die Klassendatei JarResources.java//www.javaworld.com/javatips/javatip49/JarResources.java
  • JARs //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • Weitere Informationen zur Archivierungsunterstützung in Java finden Sie unter "Java-Tipp 21Verwenden Sie Archivdateien, um das Laden von Applets zu beschleunigen" //www.javaworld.com/javatips/jw-javatip21.html

Diese Geschichte "Java-Tipp 49: Extrahieren von Java-Ressourcen aus JAR- und Zip-Archiven" wurde ursprünglich von JavaWorld veröffentlicht.