JarファイルのI/Oについて

javaでJarファイルのI/Oをするには、java.util.jarパッケージ配下のクラス郡を使う。

読み取り

 File file = new File("hoge.jar");
 JarFile jarFile = new JarFile(file);
 JarEntry jarEntry = jarFile.getJarEntry("entryname");
 InputStream in = jarFile.getInputStream(jarEntry);

書き込み

書き込みには、JarOutputStreamを使用する。

 File file = new File("hoge.jar");
 JarOutputStream out = new JarOutputStream(new FileOutputStream(file));

複数のファイルを一つのJarファイルに格納したい場合は、JarOutputStream#putNextEntry()を使用する。

File file = new File("hoge.jar");
// ストリームを開く。
JarOutputStream out = new JarOutputStream(new FileOutputStream(file));
// 最初のエントリを書く。
JarEntry jarEntry_01 = new JarEntry("jarEntry_01");
out.putNextEntry(jarEntry_01);
out.write("これはjarEntry_01".getBytes());
out.closeEntry();
// 2番目のエントリを書く。
JarEntry jarEntry_02 = new JarEntry("jarEntry_02");
out.putNextEntry(jarEntry_02);
out.write("これはjarEntry_02".getBytes());
out.closeEntry();
// ストリームを閉じる。
out.close();

最初のエントリを書き込んだ後に、closeEntry()を呼び出しているが、
2回目のputNextEntry()呼び出し時に、内部でcloseEntry()を呼び出しているので、もしかしたら明示的にcloseEntry()を呼び出す必要は無いかもしれない。
上記コードを実行すると、hoge.jarが作成される。
作成されたhoge.jarを、jarコマンドを使用して中を見てみると、以下のような感じになる。

>jar tvf hoge.jar
    17 Thu Sep 03 03:28:52 JST 2009 jarEntry_01
    17 Thu Sep 03 03:28:52 JST 2009 jarEntry_02

Jarファイルのフォーマットは、通常のZipファイルのフォーマットとほぼ同じなので、絵で表すと↓みたいな感じになっている。

ファイルの末尾に、ファイルヘッダ情報を持っていて、そこに、各エントリの開始位置が記載されている。
なので、JarEntry#close()を呼び出した時に、今まで書き込んだ各JarEntryの情報が書き込まれる。
作成されたhoge.jarを、バイナリエディタで見てみると、以下のような感じになる。

http://www.pkware.com/documents/casestudies/APPNOTE.TXT