Javaのヒント49:JARおよびzipアーカイブからJavaリソースを抽出する方法

ほとんどのJavaプログラマーは、JARファイルを使用してJavaソリューションを構成するさまざまなリソース(つまり、.classファイル、サウンド、およびイメージ)をすべてバンドルすることの利点をかなり明確にしています。(JARファイルに慣れていない場合は、以下の「リソース」セクションを確認してください。)JARファイルをトリックのバッグに組み込み始めたばかりの人からよく寄せられる質問は、「JARファイルから画像を抽出するにはどうすればよいですか。 JAR?」その質問に答えて、JARから任意のリソースを非常に簡単に抽出できるようにするクラスを提供します。

GIF画像の読み込み

アプリケーションで使用したい.gif画像ファイルの束を含むJARファイルがあるとしましょう。JarResourcesを使用してJARから画像ファイルにアクセスする方法は次のとおりです。

JarResources jar = new JarResources( "Images.jar"); 画像ロゴ= Toolkit.getDefaultToolkit()。createImage(jar.getResource( "logo.gif");

このコードスニペットはJarResources、使用したいリソースを含むJARファイルに初期化されたオブジェクトを作成できることを示しています- Images.jar。次に、このJarResources'getResource()メソッドを使用して、AWTツールキットのcreateImage()メソッドのlogo.gifファイルから生データを提供します。

ネーミングに関する注意

JarResourceは、Java1.1が提供するさまざまな機能を使用してJARおよびzipアーカイブファイルを操作する方法のかなり簡単な例です。

命名についての簡単なメモ。Javaでのアーカイブのサポートは、実際には一般的なzipアーカイブ形式を使用して開始されました(「Javaのヒント21:アーカイブファイルを使用してアプレットの読み込みを高速化する」を確認してください)。したがって、元々、アーカイブファイルを操作するためのJavaサポートの実装では、すべてのクラスとその他のものがjava.util.zipパッケージに配置されていました。これらのクラスは「Zip。」で始まる傾向があります。しかし、Java 1.1への移行のどこかで、アーカイブの名前がよりJavaに焦点を当てるように変更された権限。したがって、現在JARファイルと呼んでいるのは基本的にzipファイルです。

使い方

JarResourcesクラスの重要なデータフィールドは、指定されたJARファイルの内容を追跡および保存するために使用されます。

public final class JarResources {public boolean debugOn = false; プライベートハッシュテーブルhtSizes = new Hashtable(); プライベートハッシュテーブルhtJarContents = new Hashtable(); プライベート文字列jarFileName;

したがって、クラスのインスタンス化により、JARファイルの名前が設定され、init()メソッドが呼び出されて、実際のすべての作業が実行されます。

public JarResources(String jarFileName){this.jarFileName = jarFileName; 初期化(); }

現在、このinit()メソッドは、指定されたJARファイルの内容全体をハッシュテーブル(リソースの名前を介してアクセス)にロードするだけです。

これはかなり重い方法なので、もう少し詳しく見ていきましょう。このZipFileクラスは、JAR / zipアーカイブヘッダー情報への基本的なアクセスを提供します。これは、ファイルシステムのディレクトリ情報に似ています。ここでは、のすべてのエントリを列挙し、アーカイブ内の各リソースのサイズを使用ZipFileしてhtSizesハッシュテーブルを作成します。

private void init(){try {ZipFile zf = new ZipFile(jarFileName); 列挙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();

次に、ZipInputStreamクラスを使用してアーカイブにアクセスします。このZipInputStreamクラスは、アーカイブ内の個々のリソースをそれぞれ読み取ることができるように、すべての魔法を実行します。各リソースを構成するアーカイブから正確なバイト数を読み取り、そのデータをリソース名でアクセス可能なhtJarContentsハッシュテーブルに格納します。

FileInputStream fis = new FileInputStream(jarFileName); BufferedInputStream bis = new BufferedInputStream(fis); ZipInputStream zis = new ZipInputStream(bis); ZipEntry ze = null; while((ze = zis.getNextEntry())!= null){if(ze.isDirectory()){続行; } if(debugOn){System.out.println( "ze.getName()=" + ze.getName()+ "、" + "getSize()=" + ze.getSize()); } int size =(int)ze.getSize(); //-1はサイズが不明であることを意味します。 if(size ==-1){size =((Integer)htSizes.get(ze.getName()))。intValue(); } byte [] b = new byte [(int)size]; int rb = 0; intチャンク= 0; while(((int)size-rb)> 0){chunk = zis.read(b、rb、(int)size-rb); if(chunk ==-1){break; } rb + =チャンク; } //内部リソースにハッシュテーブルを追加します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(); }}

各リソースを識別するために使用される名前は、アーカイブ内のリソースの修飾パス名であり、たとえば、パッケージ内のクラスの名前ではないことに注意してください。つまり、ZipEntryjava.util.zipパッケージのクラスは「java.util.zip.ZipEntry」ではなく「java / util / zip / ZipEntry」という名前にします。

コードの最後の重要な部分は、単純なテストドライバーです。テストドライバーは、JAR / zipアーカイブ名とリソースの名前を取得する単純なアプリケーションです。アーカイブ内のリソースを見つけようとし、その成功または失敗を報告します。

public static void main(String [] args)throws 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( "Could not find" + args [1] + "。"); } else {System.out.println( "Found" + args [1] + "(length =" + buff.length + ")。"); }}} // JarResourcesクラスの終わり。

そして、あなたはそれを持っています。JARファイルに隠されたリソースの使用に伴うすべての混乱を隠す使いやすいクラス。

読者のための演習

アーカイブファイルからリソースを抽出する感覚が得られたので、JarResourcesクラスを変更および拡張する際に検討する必要のあるいくつかの指示を次に示します。

  • 構築中にすべてをロードする代わりに、遅延ロードを実行します。大きなJARファイルの場合、構築中にすべてのファイルをロードするのに十分なメモリがない可能性があります。
  • のような汎用アクセサメソッドを単に提供する代わりに、getResource()他のリソース固有のアクセサを提供することもできます。たとえば、getImage()JavaImageオブジェクトgetClass()を返す、、 JavaClassオブジェクトを返す(カスタマイズされたクラスローダーの助けを借りて)などです。JARファイルが十分に小さい場合は、拡張子(.gif、.classなど)に基づいてすべてのリソースを事前にビルドできます。
  • 一部のメソッドは、次のような、指定されたJARファイル自体(基本的にはラッパーZipFile)に関する情報を提供する必要があります。Jar/ zipエントリの数。リソースのすべての名前を返す列挙子。特定のエントリの長さ(およびその他の属性)を返すアクセサ。いくつか例を挙げると、索引付けを可能にするアクセサー。
  • JarResourcesアプレットで使用するように拡張できます。アプレットのパラメータとURLConnectionクラスを利用することで、アーカイブをローカルファイルとして開く代わりに、JARコンテンツをネットワークからダウンロードできます。さらに、このクラスをカスタムJavaコンテンツハンドラーとして拡張することもできます。

結論

JARファイルから画像を抽出する方法を知りたがっている場合は、今すぐ方法があります。 JARファイルを使用して画像を処理できるだけでなく、このヒントで提供される新しいクラスを使用して、JARから任意のリソースに対して抽出マジックを実行できます。

Arthur Choiは現在、IBMでアドバイザリープログラマーとして働いています。彼はSamSungNetworkLaboratoryやMITREを含むいくつかの会社で働いてきました。彼が取り組んできたさまざまなプロジェクトは、クライアント/サーバーシステム、分散オブジェクトコンピューティング、およびネットワーク管理です。彼はさまざまなオペレーティングシステム環境で多くの言語を使用してきました。彼は1981年にFORTRANIVとCOBOLでプログラミングを開始しました。その後、彼はCとC ++に切り替え、Javaを約2年間使用しています。彼は、ワイドエリアネットワークを介したデータリポジトリの領域でのJavaのアプリケーション、およびインターネットを介した並列分散処理(エージェントベースのプログラミングを使用)に最も興味を持っています。従業員、コンサルタント、および自社のプリンシパルであるJohn Mitchellは、過去10年間、最先端のコンピューターソフトウェアの開発に投資してきました。他の開発者へのアドバイスとトレーニング。彼は、Javaテクノロジ、コンパイラ、インタプリタ、Webベースのアプリケーション、およびインターネットコマースに関するコンサルティングを提供してきました。 Johnは、Making Sense of Java:A Guide for Managers and the Rest of Usを共著し、プログラミングジャーナルに記事を掲載しています。彼は、JavaWorldのJavaヒント列を作成することに加えて、comp.lang.tcl.announceおよびcomp.binaries.geosニュースグループをモデレートします。

このトピックの詳細

  • これがクラスファイルJarResources.java//www.javaworld.com/javatips/javatip49/JarResources.javaです。
  • JAR //www.javasoft.com/products/jdk/1.1/docs/guide/jar/index.html
  • Javaでのアーカイブサポートの詳細については、「Javaヒント21アーカイブファイルを使用してアプレットのロードを高速化する」を参照してください。//www.javaworld.com/javatips/jw-javatip21.html

この記事「Javaのヒント49:JARおよびzipアーカイブからJavaリソースを抽出する方法」は、もともとJavaWorldによって公開されました。