Tip 49 Java: Cara mengekstrak sumber daya Java dari JAR dan arsip zip

Sebagian besar programmer Java cukup jelas tentang keuntungan menggunakan file JAR untuk menggabungkan semua sumber daya (yaitu, file .class, suara, dan gambar) yang membentuk solusi Java mereka. (Jika Anda tidak terbiasa dengan file JAR, lihat bagian Sumber daya di bawah.) Pertanyaan yang sangat umum yang diajukan oleh orang-orang yang baru mulai memasukkan file JAR ke dalam kumpulan trik mereka adalah, "Bagaimana cara mengekstrak gambar dari BOTOL?" Kami akan menjawab pertanyaan itu dan menyediakan kelas yang membuatnya sangat mudah untuk mengekstrak sumber daya apa pun dari JAR!

Memuat gambar GIF

Katakanlah kita memiliki file JAR yang berisi banyak file gambar .gif yang ingin kita gunakan dalam aplikasi kita. Inilah cara kami mengakses file gambar dari JAR menggunakan JarResources:

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

Potongan kode tersebut menunjukkan bahwa kita dapat membuat JarResourcesobjek yang diinisialisasi ke file JAR yang berisi sumber daya yang ingin kita gunakan - Images.jar. Kami kemudian menggunakan JarResources'getResource()metode untuk menyediakan data mentah dari file logo.gif untuk metode toolkit AWT createImage().

Catatan tentang penamaan

JarResource adalah contoh yang cukup mudah tentang bagaimana menggunakan berbagai fasilitas yang disediakan oleh Java 1.1 untuk memanipulasi file arsip JAR dan zip.

Catatan singkat tentang penamaan. Dukungan pengarsipan di Java sebenarnya dimulai menggunakan format pengarsipan zip yang populer (lihat "Tip Java 21: Gunakan file arsip untuk mempercepat pemuatan applet"). Jadi, awalnya, dalam mengimplementasikan dukungan Java untuk memanipulasi file arsip, semua kelas dan yang lainnya ditempatkan di paket java.util.zip; kelas-kelas ini cenderung dimulai dengan " Zip." Tapi di suatu tempat di pindah ke Java 1.1, kekuatan yang diubah nama arsip menjadi lebih fokus pada Java. Karenanya, apa yang sekarang kita sebut file JAR pada dasarnya adalah file zip.

Bagaimana itu bekerja

Bidang data penting untuk JarResourceskelas digunakan untuk melacak dan menyimpan konten file JAR yang ditentukan:

kelas akhir publik JarResources {public boolean debugOn = false; private Hashtable htSizes = new Hashtable (); pribadi Hashtable htJarContents = baru Hashtable (); private String jarFileName;

Jadi, instantiation kelas menetapkan nama file JAR dan kemudian memanggil init()metode untuk melakukan semua pekerjaan nyata:

publik JarResources (String jarFileName) {this.jarFileName = jarFileName; init (); }

Sekarang, init()metode ini cukup banyak memuat seluruh konten file JAR yang ditentukan ke dalam hashtable (diakses melalui nama sumber daya).

Ini adalah metode yang cukup kuat, jadi mari kita uraikan lebih jauh. The ZipFilekelas memberi kita akses dasar ke JAR / zip informasi header arsip. Ini mirip dengan informasi direktori dalam sistem file. Di sini kita menghitung melalui semua entri di ZipFiledan membangun hashtable htSizes dengan ukuran setiap sumber daya di arsip:

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

Selanjutnya, kami mengakses arsip melalui penggunaan ZipInputStreamkelas. The ZipInputStreamkelas tidak semua sihir untuk memungkinkan kita untuk membaca setiap sumber daya individu dalam arsip. Kami membaca jumlah persis byte dari arsip yang menyusun setiap sumber daya dan menyimpan data itu ke dalam hashtable htJarContents yang dapat diakses dengan nama sumber daya:

FileInputStream fis = FileInputStream baru (jarFileName); BufferedInputStream bis = new BufferedInputStream (fis); ZipInputStream zis = new ZipInputStream (bis); ZipEntry ze = null; sementara ((ze = zis.getNextEntry ())! = null) {if (ze.isDirectory ()) {lanjutkan; } if (debugOn) {System.out.println ("ze.getName () =" + ze.getName () + "," + "getSize () =" + ze.getSize ()); } ukuran int = (int) ze.getSize (); // -1 berarti ukuran tidak diketahui. if (size == - 1) {size = ((Integer) htSizes.get (ze.getName ())). intValue (); } byte [] b = byte baru [(int) size]; int rb = 0; int potongan = 0; sementara (((int) size - rb)> 0) {chunk = zis.read (b, rb, (int) size - rb); if (chunk == - 1) {break; } rb + = potongan; } // tambahkan ke sumber daya internal htJarContents.put (ze.getName (), b); if (debugOn) {System.out.println (ze.getName () + "rb =" + rb + ", size =" + size + ", csize =" + ze.getCompressedSize ()); }}} menangkap (NullPointerException e) {System.out.println ("selesai."); } menangkap (FileNotFoundException e) {e.printStackTrace (); } menangkap (IOException e) {e.printStackTrace (); }}

Perhatikan bahwa nama yang digunakan untuk mengidentifikasi setiap sumber daya adalah nama jalur sumber daya yang memenuhi syarat dalam arsip, bukan , misalnya, nama kelas dalam paket - yaitu, ZipEntrykelas dari paket java.util.zip akan diberi nama "java / util / zip / ZipEntry", bukan "java.util.zip.ZipEntry."

Bagian penting terakhir dari kode ini adalah driver tes sederhana. Test driver adalah aplikasi sederhana yang menggunakan nama arsip JAR / zip dan nama sumber daya. Ia mencoba menemukan sumber daya di arsip dan melaporkan keberhasilan atau kegagalannya:

public static void main (String [] args) melempar IOException {if (args.length! = 2) {System.err.println ("usage: java JarResources"); System.exit (1); } JarResources jr = new JarResources (args [0]); byte [] buff = jr.getResource (args [1]); if (buff == null) {System.out.println ("Tidak dapat menemukan" + args [1] + "."); } lain {System.out.println ("Ditemukan" + args [1] + "(length =" + buff.length + ")."); }}} // Akhir dari kelas JarResources.

Dan begitulah. Kelas yang mudah digunakan yang menyembunyikan semua kekacauan yang terkait dengan penggunaan sumber daya yang tersimpan dalam file JAR.

Latihan untuk pembaca

Sekarang setelah Anda merasakan mengekstrak sumber daya dari file arsip, berikut adalah beberapa arahan yang mungkin ingin Anda jelajahi dalam memodifikasi dan memperluas JarResourceskelas:

  • Alih-alih memuat semuanya selama konstruksi, lakukan pemuatan tertunda. Dalam kasus file JAR yang besar, mungkin tidak ada cukup memori untuk memuat semua file selama konstruksi.
  • Alih-alih hanya menyediakan metode pengakses umum seperti getResource(), kita dapat menyediakan pengakses khusus sumber daya lainnya - misalnya, getImage()yang mengembalikan Imageobjek Java getClass(), yang mengembalikan Classobjek Java (dengan bantuan dari pemuat kelas yang disesuaikan), dan seterusnya. Jika file JAR cukup kecil, kita dapat membuat semua resource sebelumnya berdasarkan ekstensinya (.gif, .class, dan seterusnya).
  • Beberapa metode harus memberikan informasi tentang file JAR itu sendiri (pada dasarnya adalah pembungkus ZipFile), termasuk: jumlah entri Jar / zip; pencacah yang mengembalikan semua nama sumber daya; pengakses yang mengembalikan panjang (dan atribut lainnya) dari entri tertentu; dan pengakses yang memungkinkan pengindeksan, untuk beberapa nama.
  • JarResourcesdapat diperpanjang untuk digunakan oleh applet. Dengan memanfaatkan parameter applet dan URLConnectionkelasnya, konten JAR dapat diunduh dari jaringan alih-alih membuka arsip sebagai file lokal. Selanjutnya, kami dapat memperluas kelas ini sebagai pengendali konten Java khusus.

Kesimpulan

Jika Anda sudah lama ingin tahu cara mengekstrak gambar dari file JAR, sekarang Anda punya caranya. Anda tidak hanya dapat menangani gambar dengan file JAR, tetapi dengan kelas baru yang disediakan di tip ini, Anda juga dapat melakukan keajaiban ekstraksi pada sumber daya apa pun dari JAR.

Arthur Choi saat ini bekerja untuk IBM sebagai programmer penasihat. Dia telah bekerja untuk beberapa perusahaan, termasuk SamSung Network Laboratory dan MITRE. Berbagai proyek yang pernah dikerjakannya adalah sistem klien / server, komputasi objek terdistribusi, dan manajemen jaringan. Dia telah menggunakan sejumlah bahasa di berbagai lingkungan sistem operasi. Dia memulai pemrograman pada tahun 1981 dengan FORTRAN IV dan COBOL. Kemudian, dia beralih ke C dan C ++, dan dia telah bekerja dengan Java selama sekitar dua tahun. Dia paling tertarik pada aplikasi Java di area repositori data melalui jaringan area luas, dan pemrosesan paralel dan terdistribusi melalui Internet (menggunakan pemrograman berbasis agen). John Mitchell, seorang karyawan, konsultan, dan prinsipal perusahaannya sendiri, telah menginvestasikan sepuluh tahun terakhir dalam pengembangan perangkat lunak komputer mutakhir,dan dalam menasihati dan melatih pengembang lain. Dia telah memberikan konsultasi tentang teknologi Java, penyusun, juru bahasa, aplikasi berbasis web, dan perdagangan Internet. John ikut menulis Making Sense of Java: A Guide for Managers and the Rest of Us dan telah menerbitkan artikel di jurnal pemrograman. Selain menulis kolom Tips Java untuk JavaWorld, dia menjadi moderator di grup berita comp.lang.tcl.announce dan comp.binaries.geos.

Pelajari lebih lanjut tentang topik ini

  • Ini adalah file kelas JarResources.java//www.javaworld.com/javatips/javatip49/JarResources.java
  • JARs //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • Untuk informasi lebih lanjut tentang dukungan pengarsipan di Java, lihat "Tip Java 21Menggunakan file arsip untuk mempercepat pemuatan applet" //www.javaworld.com/javatips/jw-javatip21.html

Artikel ini, "Tip Java 49: Cara mengekstrak sumber daya Java dari JAR dan arsip zip" awalnya diterbitkan oleh JavaWorld.