jarファイルはJava言語でよく利用されるファイル圧縮/アーカイブ形式で、内部的には、zip形式と同じ仕様を採用しています。ただし、単にzip形式を採用しているのではなく、マニフェスト機能などが付与されています。
jarファイルはコンパイル後のclassファイルをまとめる目的でよく利用されます。具体的には、Javaクラスライブラリの配布形式を作成する場合や、Webなどにデプロイするためのファイルを作成する過程などで利用されます。
「Java Archive(JAR)ファイル」に公式ドキュメントがあります。
ビルドプロセスの自動化の観点から、jarファイル作成などのモジュール作成手順を自動化しておくことは、現実的なソフトウェア開発において重要なことの1つです。このような自動化のためのスキルは、専門技能として世間で認識されているほどです。
記事執筆時点では、ビルドプロセスなどの自動化にはApache Ant(あるいは、Apache Maven)がよく利用されます。
一方、JDK(Java SE Development Kit)では、jarファイル作成のために、jarコマンドが提供されています。jarコマンドについては、「jar - Java Archive ツール(Windows版)」に公式ドキュメントがあります。単にjarファイルを作成したい場合などには、こちらのコマンドを利用することもあります。
通常は、Apache Antやjarコマンドでjarファイルを作成するものなのですが、ここではJava APIを利用してjarファイルを作成するサンプルを見ていきましょう。
jarファイルを作成するには、java.util.jar.JarOutputStreamクラスを利用します。APIはjava.util.zip.ZipOutputStreamの使い方によく似ています。ただしjarファイルの場合は、java.util.jar.Manifestクラスのインスタンスをコンストラクタに与えている点が異なります。
jarファイルを作成するサンプル |
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
/** jarファイルを作成するサンプル */
public class CreateJarSample {
public static void main(String[] args) {
try {
final File file = new File("jarsample.jar");
System.out.println("jarファイル作成: 開始: " +
file.getAbsolutePath());
new CreateJarSample().process(file);
System.out.println("jarファイル作成: 終了");
} catch (IOException e) {
System.out.println("jarファイル作成中に"+
"例外が発生しました。処理中断します:" +
e.toString());
}
}
/**
* jarファイルを作成します
*
* @param file 出力するjarファイル
* @throws IOException 入出力例外が発生した場合
*/
public void process(final File file) throws IOException {
/* マニフェストの作成 */
final Manifest manifest = new Manifest();
final Attributes attrManifest
= manifest.getMainAttributes();
attrManifest.put(Attributes.Name.MANIFEST_VERSION, "1.0");
final String javaVendor
= System.getProperty("java.vendor");
final String javaVersion
= System.getProperty("java.version");
attrManifest.put(new Attributes.Name("Created-By"),
javaVersion + " ("
+ javaVendor + ")");
final JarOutputStream jarOutStream = new JarOutputStream(
new BufferedOutputStream(
new FileOutputStream(file)), manifest);
try {
{
/* ディレクトリの作成 */
final JarEntry entry = new JarEntry("ABC/");
entry.setMethod(JarEntry.STORED);
entry.setSize(0);
entry.setCrc(0);
jarOutStream.putNextEntry(entry);
jarOutStream.closeEntry();
}
{
final JarEntry entry = new JarEntry("ABC/ABC.txt");
jarOutStream.putNextEntry(entry);
/* ファイルデータの書き込み */
jarOutStream.write(
new String("あいうえお").getBytes());
jarOutStream.closeEntry();
}
{
final JarEntry entry = new JarEntry("ABC/DEF.txt");
jarOutStream.putNextEntry(entry);
jarOutStream.write(
new String("かきくけこ").getBytes());
jarOutStream.closeEntry();
}
{
final JarEntry entry = new JarEntry("GHI.txt");
jarOutStream.putNextEntry(entry);
jarOutStream.write(
new String("さしすせそ").getBytes());
jarOutStream.closeEntry();
}
jarOutStream.finish();
} finally {
jarOutStream.close();
}
}
} |
|
jarファイル作成: 開始: C:\Documents and Settings\iga\workspace\aaa\jarsample.jar
jarファイル作成: 終了
作成したjarファイルを展開(解凍)しながら読み込むサンプルプログラムを見ていきましょう。使用するjava.util.jar.JarInputStreamクラスは基本的に、java.util.zip.ZipInputStreamと同じようなAPIになっていますが、java.util.jar.Manifestクラスを取り出すことができるようになっている点が異なります。
また、今回は展開(解凍)したファイル内容を16進文字列表示するように変えています。ここで示すソースコードをコンパイルおよび実行するためには、以前の記事で掲載したHexStringUtilクラスが必要です。
jarファイルを読み込むサンプル |
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.Map.Entry;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
/** jarファイルを読み込むサンプル */
public class ReadJarSample {
public static void main(final String[] args)
throws IOException {
try {
final File file = new File("jarsample.jar");
System.out.println("jarファイル読込: 開始: " +
file.getAbsolutePath());
new ReadJarSample().process(file);
System.out.println("jarファイル読込: 終了");
} catch (IOException e) {
System.out.println("jarファイル読込中に"+
"例外が発生しました。処理中断します:" +
e.toString());
}
}
/**
* jarファイルを読み込みます
*
* @param file 入力するjarファイル
* @throws IOException 入出力例外が発生した場合
*/
public void process(final File file) throws IOException {
final JarInputStream jarInStream = new JarInputStream(
new BufferedInputStream(new FileInputStream(file)));
try {
final Manifest manifest = jarInStream.getManifest();
if (manifest != null) {
final Attributes attrManifest
= manifest.getMainAttributes();
final Set set = attrManifest.entrySet();
System.out.println(" マニフェスト");
for (Iterator ite = set.iterator();ite.hasNext();){
final Entry entry = (Entry) ite.next();
System.out.println(" " + entry.getKey() +
": ["
+ entry.getValue() + "]");
}
}
for (;;) {
final JarEntry entry
= jarInStream.getNextJarEntry();
if (entry == null)
break;
if (entry.isDirectory()) {
System.out.println(" ディレクトリ名: [" +
entry.getName() + "]");
} else {
System.out.println(" ファイル名: [" +
entry.getName() + "]");
/* ファイルデータの読み込み。 */
final ByteArrayOutputStream outStream
= new ByteArrayOutputStream();
for (;;) {
int iRead = jarInStream.read();
if (iRead < 0)
break;
outStream.write(iRead);
}
outStream.flush();
outStream.close();
System.out.println(" 内容: [" +
HexStringUtil.bytesToHexString(
outStream.toByteArray()) + "]");
}
jarInStream.closeEntry();
}
} finally {
jarInStream.close();
}
}
} |
|
jarファイル読込: 開始: C:\Documents and Settings\iga\workspace\aaa\jarsample.jar
マニフェスト
Created-By: [1.5.0_13 (Sun Microsystems Inc.)]
Manifest-Version: [1.0]
ディレクトリ名: [ABC/]
ファイル名: [ABC/ABC.txt]
内容: [82 a0 82 a2 82 a4 82 a6 82 a8]
ファイル名: [ABC/DEF.txt]
内容: [82 a9 82 ab 82 ad 82 af 82 b1]
ファイル名: [GHI.txt]
内容: [82 b3 82 b5 82 b7 82 b9 82 bb]
jarファイル読込: 終了
ファイル圧縮に関する話題や関連するJava APIについて紹介してきましたが、いかがだったでしょうか?
今回の記事で紹介したようなJava APIを活用することによって、比較的簡単に開発しているアプリケーションにアーカイブ機能や圧縮機能を組み入れることができます。これは、とても素晴らしいことだと思います。一方で、いくつかの注意点についても紹介しました。それらの注意点にも気を付けつつ、ファイル圧縮技術をぜひ活用してください。