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

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

[伊賀敏樹,株式会社 NTTデータ ビジネスブレインズ]

ファイル展開(解凍)をしてみよう、そして「可逆圧縮」とは?

 ファイル圧縮+アーカイブしたファイルは展開(解凍)の操作によって元に戻すことができます。

 先ほどの「単調で大きなファイル.zip」をダブルクリックして開くと、中に含まれるファイルやディレクトリを表示できます。ここでは、先ほど圧縮した「単調で大きなファイル.txt」が中に含まれていることが分かります。

図8 単調で大きなファイルの圧縮フォルダの内容 図8 単調で大きなファイルの圧縮フォルダの内容

 [エクスプローラ]の[ファイルをすべて展開]メニューを選ぶと、アーカイブ内のすべてのディレクトリやファイルを展開(解凍)できます。

図9 圧縮フォルダの展開ウィザードの開始 図9 圧縮フォルダの展開ウィザードの開始
図10 展開ウィザードの展開先入力画面 図10 展開ウィザードの展開先入力画面
図11 展開ウィザードの終了画面 図11 展開ウィザードの終了画面

 展開(解凍)の結果、下記のように圧縮される前と同じ内容のファイルを取り出すことができます。

図12 展開(解凍)の結果 図12 展開(解凍)の結果

 なお、一般的なデータ圧縮には、圧縮前のデータが完全に復元される圧縮と、完全には復元されない圧縮との2種類があります。ここで紹介しているファイル圧縮(そして、今回の記事で紹介するもの)では、圧縮前のデータが完全に復元されます。

 このような圧縮のことを、「可逆圧縮」と呼びます。

Java APIで提供されているアーカイブ/圧縮機能

 Java APIでもアーカイブ/ファイル圧縮に関する機能が提供されています。標準的に利用できるアーカイブ/ファイル圧縮形式はgzipzipjarの3形式です。この3形式が標準的なAPIで利用できるのは、とても便利なことです。

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

gzipファイル形式の概要

 gzip、zip、jarの3形式のうち、gzip形式には複数のディレクトリやファイルを1つにまとめるアーカイブ機能はありません。Linuxなどでは、よくgzip形式が利用されますが、アーカイブ機能を併せて利用したい場合には、tar形式という別のアーカイブ機能を併用することによってzip形式やjar形式と同様の機能を実現することが多いです。

編集部注tarについて詳しく知りたい読者は、Linux Tips複数のファイルを1つにまとめて圧縮するにはをご参照ください。

gzipファイルを作成するサンプル

 それでは、gzip形式のファイル圧縮を見ていきましょう。gzipには、アーカイブ機能がないのでAPIは単純です。このため、ストリームプログラミングに組み込んで利用しやすくなっています。ストリームプログラミングについては、前回の記事を参照してください。

前提条件

この記事で挙げるサンプルプログラムは、現実的なプログラムで必要となる粒度の例外処理を実装していません。これは、現実的な例外処理を実装すると、APIの見通しが悪くなってしまうためです。現実的なプログラムで必要となる例外処理の粒度については、前回の記事を参照してください


 実際に、gzipファイルを作成するサンプルを見ていきましょう。gzip形式で圧縮されたファイルは伝統的に拡張子「.gz」を付けます。

gzipファイルを作成するサンプル
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;

/** gzipファイルを作成するサンプル */
public class CreateGzipSample {
    public static void main(String[] args) {
        try {
            final File file = new File("gzipsample.gz");
            System.out.println("gzipファイル作成: 開始: " +
                 file.getAbsolutePath());
            new CreateGzipSample().process(file);
            System.out.println("gzipファイル作成: 終了");
        } catch (IOException e) {
            System.out.println("gzipファイル作成中に"+
                 "例外が発生しました。処理中断します:" +
                 e.toString());
        }
    }
    /**
     * gzipファイルを作成します
     *
     * @param file 出力するgzipファイル
     * @throws IOException 入出力例外が発生した場合
     */
    public void process(final File file) throws IOException {
        final GZIPOutputStream gzipOutStream =new GZIPOutputStream(
             new BufferedOutputStream(new FileOutputStream(file)));
        try {
            /* ファイルデータの書き込み */
            gzipOutStream.write(
                new String("あいうえお。かきくけこ。").getBytes());
            gzipOutStream.finish();
        } finally {
            gzipOutStream.close();
        }
    }
}

 java.util.zip.GZIPOutputStreamクラスのオブジェクトにバイナリデータを書き込むと、gzip形式で圧縮してから連結先の出力ストリーム(ここでは、java.io.BufferedOutputStreamクラス)に渡されます。

gzipファイルを読み込むサンプル

 次に、作成したgzipファイルを展開(解凍)しながら読み込むサンプルプログラムを見ていきましょう。

 なお、このサンプルは、直前で示したCreateGzipSampleが作成したgzipファイルを読み込むという仮定の下に作られています。具体的には、読み込まれるデータは少量のテキストファイルであり、かつ同じデフォルト文字エンコーディング環境で動作しているものと仮定しています。

gzipファイルを読み込むサンプル
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;

/** gzipファイルを読み込むサンプル */
public class ReadGzipSample {
    public static void main(final String[] args)
    throws IOException {
        try {
            final File file = new File("gzipsample.gz");
            System.out.println("gzipファイル読込: 開始: " +
                file.getAbsolutePath());
            new ReadGzipSample().process(file);
            System.out.println("gzipファイル読込: 終了");
        } catch (IOException e) {
            System.out.println("gzipファイル読込中に"+
                "例外が発生しました。処理中断します:" +
                 e.toString());
        }
    }
    /**
     * gzipファイルを読み込みます
     *
     * @param file 入力するgzipファイル
     * @throws IOException 入出力例外が発生した場合
     */
    public void process(final File file) throws IOException {
        final GZIPInputStream gzipInStream = new GZIPInputStream(
            new BufferedInputStream(new FileInputStream(file)));
        try {
            /* ファイルデータの読み込み。 */
            final ByteArrayOutputStream outStream
                = new ByteArrayOutputStream();
            for (;;) {
                int iRead = gzipInStream.read();
                if (iRead < 0) break;
                outStream.write(iRead);
            }
            outStream.flush();
            outStream.close();
            System.out.println(" 内容: ["
                + new String(outStream.toByteArray()) + "]");
        } finally {
            gzipInStream.close();
        }
    }
}

 ここでは、java.util.zip.GZIPInputStreamクラスを使用しています。連結先の入力ストリーム(ここでは、java.io.BufferedInputStreamクラス)からデータをgzip形式で展開(解凍)しながら読み込んでいます。

 さらに次ページでは、java.util.zipパッケージでzipファイルを操作する方法を見ていきましょう。

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

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

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

メールマガジン登録

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