連載
» 2007年10月24日 00時00分 公開

プログラマーの常識をJavaで身につける(8):意外と知らないファイル圧縮技術の常識 (4/4)

[伊賀敏樹,株式会社 NTTデータ ビジネスブレインズ]
前のページへ 1|2|3|4       

java.util.jarパッケージでjarファイルを操作

jarファイル形式の概要

 jarファイルはJava言語でよく利用されるファイル圧縮/アーカイブ形式で、内部的には、zip形式と同じ仕様を採用しています。ただし、単にzip形式を採用しているのではなく、マニフェスト機能などが付与されています。

 jarファイルはコンパイル後のclassファイルをまとめる目的でよく利用されます。具体的には、Javaクラスライブラリの配布形式を作成する場合や、Webなどにデプロイするためのファイルを作成する過程などで利用されます。

 「Java Archive(JAR)ファイル」に公式ドキュメントがあります。

jarファイル作成手順の自動化

 ビルドプロセスの自動化の観点から、jarファイル作成などのモジュール作成手順を自動化しておくことは、現実的なソフトウェア開発において重要なことの1つです。このような自動化のためのスキルは、専門技能として世間で認識されているほどです。

 記事執筆時点では、ビルドプロセスなどの自動化にはApache Ant(あるいは、Apache Maven)がよく利用されます。

編集部注Antについて詳しく知りたい読者は、連載「現場に活かす Jakarta Project」第2回「AntでJavaのビルドを簡単にする」を、Mavenについては、「Java開発支援ツールの定番」の[Maven]をご参照ください。

 一方、JDK(Java SE Development Kit)では、jarファイル作成のために、jarコマンドが提供されています。jarコマンドについては、「jar - Java Archive ツール(Windows版)」に公式ドキュメントがあります。単にjarファイルを作成したい場合などには、こちらのコマンドを利用することもあります。

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ファイルを読み込むサンプル

 作成した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を活用することによって、比較的簡単に開発しているアプリケーションにアーカイブ機能や圧縮機能を組み入れることができます。これは、とても素晴らしいことだと思います。一方で、いくつかの注意点についても紹介しました。それらの注意点にも気を付けつつ、ファイル圧縮技術をぜひ活用してください。

筆者紹介

blanco Framework(コミッタ)

伊賀 敏樹(いが としき)
ハンドル:いがぴょん

1968年生まれ。現在、NTTデータ ビジネスブレインズ 第一SI事業部 ソリューショングループ所属。システム開発の技術支援などに従事する。仕事におけるJava言語とのかかわりは1998年から。 現在 blanco Frameworkというオープンソースによるソースコード自動生成タイプの開発フレームワーク提供に取り組んでいる。 趣味はヴァイオリン演奏。アマチュアオーケストラで演奏することもある。

ホームページ
いがぴょんの日記ウェブページv2(1996年から続けているWeb日記)

主な著書
やさしく学ぶ基礎からのJDBC
Javaプログラミング[アプリケーション編]ステップアップラーニング



前のページへ 1|2|3|4       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。