Java Tip 49: Jak wyodrębnić zasoby Java z archiwów JAR i ZIP

Większość programistów Java jest całkiem jasnych co do zalet używania pliku JAR do spakowania wszystkich różnych zasobów (czyli plików .class, dźwięków i obrazów), które składają się na ich rozwiązanie Java. (Jeśli nie znasz plików JAR, zapoznaj się z sekcją Zasoby poniżej). Bardzo częstym pytaniem zadawanym przez osoby, które dopiero zaczynają włączać pliki JAR do swojego zestawu sztuczek, jest „Jak wyodrębnić obraz z pliku SŁOIK?" Odpowiemy na to pytanie i zapewnimy klasę, która sprawi, że wydobycie dowolnego zasobu z JAR będzie bardzo proste!

Ładowanie obrazu GIF

Powiedzmy, że mamy plik JAR zawierający kilka plików graficznych .gif, których chcemy użyć w naszej aplikacji. Oto jak możemy uzyskać dostęp do pliku obrazu z JAR za pomocą JarResources:

JarResources jar = nowy JarResources ("Images.jar"); Logo obrazu = Toolkit.getDefaultToolkit (). CreateImage (jar.getResource ("logo.gif");

Ten fragment kodu pokazuje, że możemy utworzyć JarResourcesobiekt zainicjowany w pliku JAR zawierającym zasób, którego chcemy użyć - Images.jar. Następnie używamy tej JarResources'getResource()metody, aby dostarczyć surowe dane z pliku logo.gif dla metody zestawu narzędzi AWT createImage().

Uwaga dotycząca nazewnictwa

JarResource jest dość prostym przykładem wykorzystania różnych udogodnień dostarczonych przez Javę 1.1 do manipulowania plikami JAR i archiwami zip.

Krótka uwaga na temat nazywania. Obsługa archiwizacji w Javie faktycznie zaczęła się przy użyciu popularnego formatu archiwizacji zip (zobacz „Java Tip 21: Użyj plików archiwalnych, aby przyspieszyć ładowanie apletów”). Tak więc, pierwotnie, wdrażając obsługę Javy do manipulowania plikami archiwum, wszystkie klasy i tak dalej zostały umieszczone w pakiecie java.util.zip; te klasy zwykle zaczynają się od „ Zip.” Ale gdzieś w przejściu na Javę 1.1 uprawnienia, które zostały zmienione, zmieniły nazwę archiwum, aby bardziej skoncentrować się na Javie. Dlatego to, co teraz nazywamy plikami JAR, to w zasadzie pliki zip.

Jak to działa

Ważne pola danych dla JarResourcesklasy służą do śledzenia i przechowywania zawartości określonego pliku JAR:

public final class JarResources {public boolean debugOn = false; private Hashtable htSizes = new Hashtable (); private Hashtable htJarContents = new Hashtable (); private String jarFileName;

Tak więc tworzenie instancji klasy ustawia nazwę pliku JAR, a następnie wywołuje init()metodę, aby wykonać całą prawdziwą pracę:

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

Teraz init()metoda prawie po prostu ładuje całą zawartość określonego pliku JAR do tablicy haszującej (dostępnej za pośrednictwem nazwy zasobu).

Jest to dość mocna metoda, więc omówmy ją nieco dalej. ZipFileKlasa daje nam podstawowy dostęp do JAR / Zip archiwum informacji nagłówka. Jest to podobne do informacji o katalogu w systemie plików. Tutaj wyliczamy wszystkie wpisy w ZipFilei budujemy hashtable htSizes z rozmiarem każdego zasobu w archiwum:

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

Następnie uzyskujemy dostęp do archiwum za pomocą ZipInputStreamklasy. ZipInputStreamKlasa robi wszystko magii, aby umożliwić nam czytać każdy z poszczególnych zasobów w archiwum. Odczytujemy dokładną liczbę bajtów z archiwum, które zawiera każdy zasób i przechowujemy te dane w tablicy haszującej htJarContents dostępnej po nazwie zasobu:

FileInputStream fis = nowy FileInputStream (jarFileName); BufferedInputStream bis = new BufferedInputStream (fis); ZipInputStream zis = nowy ZipInputStream (bis); ZipEntry ze = null; while ((ze = zis.getNextEntry ())! = null) {if (ze.isDirectory ()) {kontynuuj; } if (debugOn) {System.out.println ("ze.getName () =" + ze.getName () + "," + "getSize () =" + ze.getSize ()); } int size = (int) ze.getSize (); // -1 oznacza nieznany rozmiar. if (size == - 1) {size = ((Integer) htSizes.get (ze.getName ())). intValue (); } bajt [] b = nowy bajt [(int) rozmiar]; int rb = 0; int chunk = 0; while (((int) size - rb)> 0) {chunk = zis.read (b, rb, (int) size - rb); if (chunk == - 1) {przerwa; } rb + = chunk; } // dodaj do wewnętrznej tablicy haszowania zasobów 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 ("gotowe"); } catch (FileNotFoundException e) {e.printStackTrace (); } catch (IOException e) {e.printStackTrace (); }}

Należy zauważyć, że nazwa używana do identyfikacji każdego zasobu to kwalifikowana nazwa ścieżki zasobu w archiwum, a nie na przykład nazwa klasy w pakiecie - to znaczy ZipEntryklasa z pakietu java.util.zip nazywać się „java / util / zip / ZipEntry” zamiast „java.util.zip.ZipEntry”.

Ostatnią ważną częścią kodu jest prosty sterownik testowy. Sterownik testowy to prosta aplikacja, która pobiera nazwę archiwum JAR / zip oraz nazwę zasobu. Próbuje znaleźć zasób w archiwum i zgłasza jego powodzenie lub niepowodzenie:

public static void main (String [] args) rzuca IOException {if (args.length! = 2) {System.err.println ("użycie: java JarResources"); System.exit (1); } JarResources jr = nowe JarResources (argumenty [0]); byte [] buff = jr.getResource (args [1]); if (buff == null) {System.out.println ("Nie można znaleźć" + argumenty [1] + "."); } else {System.out.println ("Znaleziono" + args [1] + "(length =" + buff.length + ")."); }}} // Koniec klasy JarResources.

I masz to. Prosta w użyciu klasa, która ukrywa cały bałagan związany z używaniem zasobów ukrytych w plikach JAR.

Ćwiczenia dla czytelnika

Teraz, gdy masz już wyczucie, jak wyodrębniać zasoby z pliku archiwum, oto kilka wskazówek, które możesz chcieć zbadać podczas modyfikowania i rozszerzania JarResourcesklasy:

  • Zamiast ładować wszystko podczas budowy, zrób ładowanie z opóźnieniem. W przypadku dużego pliku JAR może zabraknąć pamięci do załadowania wszystkich plików podczas tworzenia.
  • Zamiast po prostu udostępniać ogólną metodę dostępu getResource(), taką jak , możemy zapewnić inne metody dostępu specyficzne dla zasobów - na przykład, getImage()które zwraca Imageobiekt Java getClass(), który zwraca Classobiekt Java (z pomocą dostosowanego programu ładującego klasy) i tak dalej. Jeśli plik JAR jest wystarczająco mały, moglibyśmy wstępnie skompilować wszystkie zasoby w oparciu o ich rozszerzenia (.gif, .class itd.).
  • Niektóre metody powinny dostarczać informacji o samym podanym pliku JAR (w zasadzie opakowanie ZipFile), w tym: liczba wpisów Jar / zip; moduł wyliczający, który zwraca wszystkie nazwy zasobów; metody dostępu, które zwracają długość (i inne atrybuty) określonego wpisu; oraz akcesor, który umożliwia indeksowanie, żeby wymienić tylko kilka.
  • JarResourcesmożna rozszerzyć do używania przez aplety. Wykorzystując parametry apletu i URLConnectionklasę, zawartość JAR można pobrać z sieci zamiast otwierać archiwa jako pliki lokalne. Ponadto możemy rozszerzyć tę klasę jako niestandardową procedurę obsługi treści Java.

Wniosek

Jeśli chciałeś wiedzieć, jak wyodrębnić obraz z pliku JAR, teraz masz na to sposób. Nie tylko możesz obsługiwać obrazy za pomocą pliku JAR, ale dzięki nowej klasie przedstawionej w tej wskazówce możesz wyodrębniać magię na dowolnym zasobie z JAR.

Arthur Choi obecnie pracuje dla IBM jako programista doradczy. Pracował dla kilku firm, w tym SamSung Network Laboratory i MITER. Różne projekty, nad którymi pracował, to systemy klient / serwer, rozproszone przetwarzanie obiektowe i zarządzanie siecią. Używał wielu języków w różnych środowiskach systemów operacyjnych. Programowanie rozpoczął w 1981 roku w FORTRAN IV i COBOL. Później przeszedł na C i C ++ i od około dwóch lat pracuje z Javą. Najbardziej interesuje go zastosowania języka Java w obszarach repozytoriów danych w sieciach rozległych oraz równoległego i rozproszonego przetwarzania przez Internet (z wykorzystaniem programowania agentowego). John Mitchell, pracownik, konsultant i dyrektor własnej firmy, przez ostatnie dziesięć lat zainwestował w rozwój najnowocześniejszego oprogramowania komputerowego,oraz doradzając i szkoląc innych programistów. Doradzał w zakresie technologii Java, kompilatorów, tłumaczy, aplikacji internetowych i handlu internetowego. John jest współautorem Making Sense of Java: A Guide for Managers and the Rest of Us i publikował artykuły w czasopismach programistycznych. Poza pisaniem kolumny porad dotyczących języka Java dla JavaWorld, moderuje także grupy dyskusyjne comp.lang.tcl.announce i comp.binaries.geos.

Dowiedz się więcej na ten temat

  • Oto plik klasy JarResources.java//www.javaworld.com/javatips/javatip49/JarResources.java
  • JAR //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • Aby uzyskać więcej informacji na temat obsługi archiwizacji w Javie, zobacz „Java Tip 21: Użyj plików archiwalnych, aby przyspieszyć ładowanie apletów” //www.javaworld.com/javatips/jw-javatip21.html

Ten artykuł „Java Tip 49: How to extract zasobów Java z archiwów JAR i zip” został pierwotnie opublikowany przez JavaWorld.