Programmering

Java Tip 49: Sådan udtrækkes Java-ressourcer fra JAR og zip-arkiver

De fleste Java-programmører er ret klare over fordelene ved at bruge en JAR-fil til at samle alle de forskellige ressourcer (dvs. klassefiler, lyde og billeder), der omfatter deres Java-løsning. (Hvis du ikke er fortrolig med JAR-filer, skal du tjekke afsnittet Ressourcer nedenfor.) Et meget almindeligt spørgsmål stillet af folk, der lige er begyndt at inkorporere JAR-filer i deres pose med tricks, er: "Hvordan udtrækker jeg et billede fra en KRUKKE?" Vi skal besvare dette spørgsmål og give en klasse, der gør det superenkelt at udtrække enhver ressource fra en JAR!

Indlæser et GIF-billede

Lad os sige, at vi har en JAR-fil, der indeholder en masse .gif-billedfiler, som vi vil bruge i vores applikation. Sådan får vi adgang til en billedfil fra JAR ved hjælp af JarResources:

 JarResources jar = nye JarResources ("Images.jar"); Billedlogo = Toolkit.getDefaultToolkit (). CreateImage (jar.getResource ("logo.gif"); 

Kodestykket viser, at vi kan oprette en JarResources objekt initialiseret til JAR-filen, der indeholder den ressource, som vi er interesserede i at bruge - Images.jar. Vi bruger derefter JarResources 'getResource () metode til at tilvejebringe rådata fra logo.gif-filen til AWT-værktøjssættet createImage () metode.

En note om navngivning

JarResource er et rimeligt ligetil eksempel på, hvordan man bruger forskellige faciliteter leveret af Java 1.1 til at manipulere JAR og zip arkivfiler.

En hurtig note om navngivning. Arkiveringsstøtte i Java startede faktisk ved hjælp af det populære zip-arkiveringsformat (se "Java Tip 21: Brug arkivfiler til at fremskynde indlæsning af applet"). Så oprindeligt, ved implementering af Java-understøttelse til at manipulere arkivfilerne, blev alle klasser og hvad der ikke blev placeret i java.util.zip-pakken; disse klasser har tendens til at starte med "Lynlås. "Men et eller andet sted i flytningen til Java 1.1 er de kræfter, der ændres, navnet på arkivet for at være mere Java-fokuseret. Derfor er det, vi nu kalder JAR-filer, stort set zip-filer.

Hvordan det virker

De vigtige datafelter til JarResources klasse bruges til at spore og gemme indholdet af den angivne JAR-fil:

offentlig endelig klasse JarResources {public boolean debugOn = false; private Hashtable htSizes = ny Hashtable (); privat Hashtable htJarContents = ny Hashtable (); privat streng jarFileName; 

Så instansen af ​​klassen indstiller navnet på JAR-filen og kalder derefter op til i det() metode til at udføre alt ægte arbejde:

 offentlige JarResources (String jarFileName) {this.jarFileName = jarFileName; i det(); } 

Nu, den i det() metode stort set bare indlæser hele indholdet af den angivne JAR-fil i en hashtable (adgang via navnet på ressourcen).

Dette er en temmelig stor metode, så lad os nedbryde den lidt længere. Det ZipFile klasse giver os grundlæggende adgang til JAR / zip arkiv headeroplysninger. Dette svarer til biblioteksoplysningerne i et filsystem. Her opregner vi alle posterne i ZipFile og opbygge htStørrelser hashtable med størrelsen på hver ressource i arkivet:

 privat ugyldigt init () {prøv {ZipFile zf = ny ZipFile (jarFileName); Optælling e = zf.entries (); mens (e.hasMoreElements ()) {ZipEntry ze = (ZipEntry) e.nextElement (); hvis (debugOn) {System.out.println (dumpZipEntry (ze)); } htSizes.put (ze.getName (), nyt heltal ((int) ze.getSize ())); } zf.close (); 

Dernæst får vi adgang til arkivet ved hjælp af ZipInputStream klasse. Det ZipInputStream klasse gør alt det magiske for at give os mulighed for at læse hver af de individuelle ressourcer i arkivet. Vi læser det nøjagtige antal bytes fra arkivet, der omfatter hver ressource, og gemmer disse data i htJarContents hashtable tilgængelig med ressource navn:

 FileInputStream fis = ny FileInputStream (jarFileName); BufferedInputStream bis = ny BufferedInputStream (fis); ZipInputStream zis = ny ZipInputStream (bis); ZipEntry ze = null; mens ((ze = zis.getNextEntry ())! = null) {hvis (ze.isDirectory ()) {fortsætter; } hvis (debugOn) {System.out.println ("ze.getName () =" + ze.getName () + "," + "getSize () =" + ze.getSize ()); } int størrelse = (int) ze.getSize (); // -1 betyder ukendt størrelse. hvis (størrelse == - 1) {størrelse = ((heltal) htSizes.get (ze.getName ())). intValue (); } byte [] b = ny byte [(int) størrelse]; int rb = 0; int klump = 0; mens (((int) størrelse - rb)> 0) {klump = zis.læs (b, rb, (int) størrelse - rb); hvis (klump == - 1) {pause; } rb + = klump; } // tilføj til intern ressource hashtable htJarContents.put (ze.getName (), b); hvis (debugOn) {System.out.println (ze.getName () + "rb =" + rb + ", størrelse =" + størrelse + ", csize =" + ze.getCompressedSize ()); }}} fangst (NullPointerException e) {System.out.println ("gjort."); } fange (FileNotFoundException e) {e.printStackTrace (); } fange (IOException e) {e.printStackTrace (); }} 

Bemærk, at navnet, der bruges til at identificere hver ressource, er det kvalificerede stinavn for ressourcen i arkivet, ikkefor eksempel navnet på en klasse i en pakke - det vil sige ZipEntry klasse fra pakken java.util.zip ville få navnet "java / util / zip / ZipEntry" snarere end "java.util.zip.ZipEntry."

Den sidste vigtige del af koden er den enkle testdriver. Testdriveren er et simpelt program, der tager et JAR / zip arkivnavn og navnet på en ressource. Det forsøger at finde ressourcen i arkivet og rapporterer dens succes eller fiasko:

 offentlig statisk ugyldig hoved (String [] args) kaster IOException {if (args.length! = 2) {System.err.println ("brug: java JarResources"); System.exit (1); } JarResources jr = nye JarResources (args [0]); byte [] buff = jr.getResource (args [1]); hvis (buff == null) {System.out.println ("Kunne ikke finde" + args [1] + "."); } andet {System.out.println ("Fundet" + args [1] + "(længde =" + buff.længde + ")."); }}} // Slutningen af ​​JarResources-klassen. 

Og der har du det. En brugervenlig klasse, der skjuler al den rodethed, der er forbundet med at bruge ressourcer gemt i JAR-filer.

Øvelser for læseren

Nu hvor du har fornemmelse af at udtrække ressourcer fra en arkivfil, er der nogle retninger, som du måske vil udforske i at ændre og udvide JarResources klasse:

  • I stedet for at indlæse alt under byggeriet skal du forsinke indlæsningen. I tilfælde af en stor JAR-fil er der muligvis ikke nok hukommelse til at indlæse alle filerne under konstruktion.
  • I stedet for blot at levere en generisk accessor-metode som getResource (), kunne vi tilbyde andre ressource-specifikke tilbehør - for eksempel getImage (), som returnerer en Java Billede objekt, getClass (), som returnerer en Java Klasse objekt (med hjælp fra en tilpasset klasselæsser) osv. Hvis JAR-filen er lille nok, kunne vi forudbygge alle ressourcer baseret på deres udvidelser (.gif, .class osv.).
  • Nogle metoder skal give information om selve den givne JAR-fil (dybest set en indpakning ZipFile), herunder: antallet af Jar / zip-poster; en tæller, der returnerer alle navnene på ressourcerne; accessors, der returnerer længden (og andre attributter) for en bestemt post; og en accessor, der tillader indeksering, for at nævne nogle få.
  • JarResources kan udvides til at blive brugt af applets. Ved at bruge appletparametre og URL-forbindelse klasse kan JAR-indholdet downloades fra netværket i stedet for at åbne arkiverne som lokale filer. Desuden kan vi udvide denne klasse som en brugerdefineret Java-indholdshåndterer.

Konklusion

Hvis du har været ivrig efter at vide, hvordan du udtrækker et billede fra en JAR-fil, har du nu en måde. Ikke kun kan du håndtere billeder med en JAR-fil, men med den nye klasse, der er angivet i dette tip, arbejder du med at udtrække magi på nogen ressource fra en JAR.

Arthur Choi arbejder i øjeblikket for IBM som en rådgivende programmør. Han har arbejdet i flere virksomheder, herunder SamSung Network Laboratory og MITRE. De forskellige projekter, som han har arbejdet med, er klient / server-systemer, distribueret objektcomputering og netværksadministration. Han har brugt en række sprog i forskellige operativsystemmiljøer. Han startede programmeringen i 1981 med FORTRAN IV og COBOL. Senere skiftede han til C og C ++, og han har arbejdet med Java i omkring to år. Han er mest interesseret i Java-applikationer inden for datalagre gennem wide-area netværk og parallel og distribueret behandling via Internettet (ved hjælp af agentbaseret programmering). John Mitchell, en medarbejder, konsulent og rektor for sin egen virksomhed, har investeret de sidste ti år i udvikling af avanceret computersoftware og i rådgivning og træning af andre udviklere. Han har ydet rådgivning om Java-teknologi, compilers, tolke, webbaserede applikationer og internethandel. John var medforfatter til Making Sense of Java: A Guide for Managers and the Rest of Us og har offentliggjort artikler i programmeringstidsskrifter. Ud over at skrive Java Tips-kolonnen til JavaWorld, modererer han nyhedsgrupperne comp.lang.tcl.announce og comp.binaries.geos.

Lær mere om dette emne

  • Her er klassefilen JarResources.java //www.javaworld.com/javatips/javatip49/JarResources.java
  • JAR //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • For mere information om arkiveringsstøtte i Java, se "Java Tip 21 Brug arkivfiler til at fremskynde indlæsning af applet" //www.javaworld.com/javatips/jw-javatip21.html

Denne historie, "Java Tip 49: Sådan udtrækkes Java-ressourcer fra JAR og zip-arkiver" blev oprindeligt udgivet af JavaWorld.