Petua Java 49: Cara mengekstrak sumber Java dari JAR dan zip arkib

Sebilangan besar pengaturcara Java cukup jelas mengenai kelebihan menggunakan fail JAR untuk mengumpulkan semua sumber (iaitu, file, suara, dan gambar .class) yang merangkumi penyelesaian Java mereka. (Sekiranya anda tidak biasa dengan fail JAR, lihat bahagian Sumber di bawah.) Soalan yang sangat umum diajukan oleh orang yang baru mula memasukkan fail JAR ke dalam beg trik mereka adalah, "Bagaimana saya mengekstrak gambar dari JAR? " Kami akan menjawab soalan itu dan menyediakan kelas untuk menjadikannya sangat mudah untuk mengekstrak sebarang sumber dari JAR!

Memuatkan gambar GIF

Katakanlah kita mempunyai fail JAR yang mengandungi sekumpulan fail gambar .gif yang ingin kita gunakan dalam aplikasi kita. Inilah cara kami dapat mengakses fail gambar dari JAR menggunakan JarResources:

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

Coretan kod itu menunjukkan bahawa kita dapat membuat JarResourcesobjek yang diinisialisasi ke fail JAR yang mengandungi sumber yang kita minat gunakan - Images.jar. Kami kemudian menggunakan JarResources'getResource()kaedah untuk memberikan data mentah dari file logo.gif untuk kaedah AWT toolkit createImage().

Catatan mengenai penamaan

JarResource adalah contoh yang mudah untuk menggunakan pelbagai kemudahan yang disediakan oleh Java 1.1 untuk memanipulasi fail arkib JAR dan zip.

Catatan ringkas mengenai penamaan. Sokongan pengarkiban di Java sebenarnya bermula dengan menggunakan format pengarkiban zip yang popular (lihat "Petua Java 21: Gunakan fail arkib untuk mempercepat pemuatan applet"). Jadi, pada asalnya, dalam melaksanakan sokongan Java untuk memanipulasi fail arkib, semua kelas dan yang lainnya diletakkan di dalam pakej java.util.zip; kelas-kelas ini cenderung bermula dengan " Zip." Tetapi di suatu tempat dalam pindah ke Java 1.1, kekuatan yang diubah nama arkib menjadi lebih fokus Java. Oleh itu, yang sekarang kita panggil fail JAR pada dasarnya adalah fail zip.

Bagaimana ia berfungsi

Medan data penting untuk JarResourceskelas digunakan untuk mengesan dan menyimpan kandungan fail JAR yang ditentukan:

kelas akhir awam JarResources {public boolean debugOn = false; Hashtabel peribadi htSizes = Hashtable baru (); Hashtable peribadi htJarContents = Hashtable baru (); String jarFileName peribadi;

Oleh itu, contoh kelas menetapkan nama fail JAR dan kemudian memanggil init()kaedah untuk melakukan semua kerja sebenar:

JarResources awam (String jarFileName) {this.jarFileName = jarFileName; di dalamnya(); }

Sekarang, init()kaedahnya hanya memuatkan keseluruhan kandungan fail JAR yang ditentukan ke dalam hashtable (diakses melalui nama sumber).

Ini adalah kaedah yang cukup besar, jadi mari kita memecahkannya lebih jauh. The ZipFilekelas memberikan kita akses asas kepada JAR / zip maklumat header arkib. Ini serupa dengan maklumat direktori dalam sistem fail. Di sini kita menghitung semua entri di dalam ZipFiledan membina htSizes hashtable dengan ukuran setiap sumber dalam arkib:

init kekosongan peribadi () {cuba {ZipFile zf = ZipFile baru (jarFileName); Penghitungan e = zf.entries (); sementara (e.hasMoreElements ()) {ZipEntry ze = (ZipEntry) e.nextElement (); jika (debugOn) {System.out.println (dumpZipEntry (ze)); } htSizes.put (ze.getName (), Integer baru ((int) ze.getSize ())); } zf.close ();

Seterusnya, kami mengakses arkib melalui penggunaan ZipInputStreamkelas. The ZipInputStreamkelas melakukan semua sihir yang membolehkan kita untuk membaca setiap satu daripada sumber individu dalam arkib. Kami membaca bilangan bait yang tepat dari arkib yang merangkumi setiap sumber dan menyimpan data tersebut ke dalam htJarContents yang boleh diakses dengan nama sumber:

FileInputStream fis = FileInputStream baru (jarFileName); BufferedInputStream bis = BufferedInputStream baru (fis); ZipInputStream zis = ZipInputStream baru (bis); ZipEntry ze = null; sementara ((ze = zis.getNextEntry ())! = null) {if (ze.isDirectory ()) {teruskan; } if (debugOn) {System.out.println ("ze.getName () =" + ze.getName () + "," + "getSize () =" + ze.getSize ()); } saiz int = (int) ze.getSize (); // -1 bermaksud ukuran yang tidak diketahui. if (size == - 1) {size = ((Integer) htSizes.get (ze.getName ())). intValue (); } bait [] b = bait baru [(int) saiz]; int rb = 0; int chunk = 0; manakala (((int) saiz - rb)> 0) {chunk = zis.read (b, rb, (int) size - rb); jika (chunk == - 1) {rehat; } rb + = bahagian; } // tambahkan ke sumber dalaman hashtable htJarContents.put (ze.getName (), b); if (debugOn) {System.out.println (ze.getName () + "rb =" + rb + ", size =" + size + ", csize =" + ze.getCompressedSize ()); }}} tangkapan (NullPointerException e) {System.out.println ("selesai."); } tangkapan (FileNotFoundException e) {e.printStackTrace (); } tangkapan (IOException e) {e.printStackTrace (); }}

Perhatikan bahawa nama yang digunakan untuk mengenal pasti setiap sumber adalah nama jalan yang layak dari sumber dalam arkib, bukan , misalnya, nama kelas dalam pakej - iaitu, ZipEntrykelas dari pakej java.util.zip akan diberi nama "java / util / zip / ZipEntry," dan bukannya "java.util.zip.ZipEntry."

Bahagian penting terakhir kod adalah pemacu ujian mudah. Pemacu ujian adalah aplikasi mudah yang mengambil nama arkib JAR / zip dan nama sumber. Ia berusaha mencari sumber dalam arkib dan melaporkan kejayaan atau kegagalannya:

public void static main (String [] args) melemparkan IOException {if (args.length! = 2) {System.err.println ("use: java JarResources"); System.exit (1); } JarResources jr = JarResources baru (args [0]); bait [] buff = jr.getResource (args [1]); if (buff == null) {System.out.println ("Tidak dapat mencari" + args [1] + "."); } lain {System.out.println ("Found" + args [1] + "(length =" + buff.length + ")."); }}} // Akhir kelas JarResources.

Dan di sana anda memilikinya. Kelas yang mudah digunakan yang menyembunyikan semua kekacauan yang terlibat dengan penggunaan sumber yang tersimpan dalam fail JAR.

Latihan untuk pembaca

Sekarang anda mempunyai perasaan untuk mengekstrak sumber dari fail arkib, berikut adalah beberapa petunjuk yang mungkin ingin anda terokai dalam mengubah dan memperluas JarResourceskelas:

  • Daripada memuatkan semuanya semasa pembinaan, jangan memuatkan yang tertunda. Sekiranya fail JAR besar, mungkin tidak ada cukup memori untuk memuatkan semua fail semasa pembinaan.
  • Daripada hanya menyediakan kaedah aksesor generik seperti getResource(), kami dapat menyediakan aksesor khusus sumber lain - misalnya, getImage()yang mengembalikan Imageobjek Java getClass(), yang mengembalikan Classobjek Java (dengan bantuan dari pemuat kelas yang disesuaikan), dan sebagainya. Sekiranya fail JAR cukup kecil, kita dapat membuat semua sumber terlebih dahulu berdasarkan peluasannya (.gif, .class, dan sebagainya).
  • Beberapa kaedah harus memberikan maklumat mengenai fail JAR yang diberikan itu sendiri (pada dasarnya pembungkus sekitar ZipFile), termasuk: bilangan entri Jar / zip; penghitung yang mengembalikan semua nama sumber; aksesori yang mengembalikan panjang (dan atribut lain) entri tertentu; dan aksesor yang membolehkan pengindeksan, untuk menamakan beberapa.
  • JarResourcesboleh diperluaskan untuk digunakan oleh applet. Dengan menggunakan parameter applet dan URLConnectionkelas, kandungan JAR dapat dimuat turun dari rangkaian dan bukannya membuka arkib sebagai fail tempatan. Selanjutnya, kami dapat memperluas kelas ini sebagai pengendali kandungan Java khusus.

Kesimpulannya

Sekiranya anda ingin mengetahui cara mengekstrak gambar dari fail JAR, kini anda sudah mendapat jalan. Bukan sahaja anda boleh mengendalikan imej dengan fail JAR, tetapi dengan kelas baru yang terdapat pada hujung ini, anda bekerja sihir mengekstrak anda pada mana-mana sumber dari balang.

Arthur Choi kini bekerja untuk IBM sebagai programmer penasihat. Dia telah bekerja di beberapa syarikat, termasuk SamSung Network Laboratory dan MITER. Berbagai projek yang telah dikerjakannya adalah sistem klien / pelayan, pengkomputeran objek terdistribusi, dan manajemen jaringan. Dia telah menggunakan sejumlah bahasa dalam berbagai lingkungan sistem operasi. Dia memulakan program pada tahun 1981 dengan FORTRAN IV dan COBOL. Kemudian, dia beralih ke C dan C ++, dan dia telah bekerja dengan Java selama lebih kurang dua tahun. Dia paling berminat dengan aplikasi Java di wilayah penyimpanan data melalui rangkaian kawasan luas, dan pemprosesan selari dan diedarkan melalui Internet (menggunakan pengaturcaraan berasaskan ejen). John Mitchell, seorang pekerja, perunding, dan prinsipal syarikatnya sendiri, telah melabur selama sepuluh tahun terakhir dalam pembangunan perisian komputer canggih,dan dalam memberi nasihat dan melatih pemaju lain. Dia telah memberikan konsultasi mengenai teknologi Java, penyusun, jurubahasa, aplikasi berbasis Web, dan perdagangan Internet. John menulis bersama Making Sense of Java: Panduan untuk Pengurus dan Selebihnya Kami dan telah menerbitkan artikel dalam jurnal pengaturcaraan. Selain menulis lajur Petua Java untuk JavaWorld, dia memoderasi kumpulan berita comp.lang.tcl.announce dan comp.binaries.geos.

Ketahui lebih lanjut mengenai topik ini

  • Berikut adalah fail kelas JarResources.java//www.javaworld.com/javatips/javatip49/JarResources.java
  • JAR //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • Untuk lebih lanjut mengenai pengarkiban di Java, lihat "Tip Java 21Gunakan fail arkib untuk mempercepat pemuatan applet" //www.javaworld.com/javatips/jw-javatip21.html

Kisah ini, "Petua Java 49: Cara mengekstrak sumber Java dari JAR dan zip arkib" pada awalnya diterbitkan oleh JavaWorld.