忍者ブログ

軽Lab

 Javaを中心とした、プログラミング関係のナレッジベース

Home > > Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

Home > > Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

- ランダム記事 -

コメント

ただいまコメントを受けつけておりません。

Home > Java > Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

今回は、Javaで7zやtar.gzなどJava標準ライブラリ上で扱えない圧縮形式を扱うライブラリApache Commons Comperssの利用方法を確認していく。


■ Apache Commons Compressライブラリについて

 Apache Commons Compressライブラリは7zを始めとする主要な圧縮形式で圧縮・解凍を行えるようになるライブラリ。ライセンスはAPACHE LICENSE 2なので商用利用も可能である。Apache Commons Compressで対応している圧縮形式は以下の通り。

表:対応フォーマット一覧(内容は主にwikipedia情報)
圧縮形式 内容
ar Unixで利用されるアーカイバ。16バイト以上のファイル名が使えない制約がある。一部システムで利用されるが、現在はtarの利用が主流である
arj 圧縮・解凍ソフトARJで圧縮されたファイル。arとは無関係な模様
cpio Unixで利用されるアーカイバ。一部システムで利用されるが、現在はtarの利用が主流である。
Z Unix compressコマンドで圧縮されたファイル。gzipのほうが圧倒的に圧縮率が高く、ライセンスの問題もあるため商用Unix以外での利用はあまりない。tarとともに利用して「*.tar.Z」「*.taz」という拡張子をつけることがある。
dump Unixでバックアップに利用される圧縮形式?
tar Unixで利用されるアーカイバ。複数ファイルを1つにまとめるだけのフォーマットであり、gzip圧縮と併用して「*.tar.gz」形式で利用するのが一般的である。
DEFLATE データ圧縮アルゴリズム。zipやgzipで利用されている。
zip Windowsで利用される圧縮形式。Java標準パッケージ(java.util.zip)でも利用可能
gzip Unixで利用される圧縮形式。アーカイブ機能はない。Java標準パッケージ(java.util.zip)でも利用可能
jar Javaのバイトコードやリソースがzip形式で圧縮されたファイル
Pack200 Java Web Startアプリのために作成された圧縮形式。数MB程度の大きさのJarファイルにおいて、内部にclassファイルしか持たない場合は1/9程度のサイズまで圧縮できる。JDK付属のpack200コマンドにより圧縮できる
bzip2 gzipやzipよりも高い圧縮率を誇る圧縮形式。処理速度はgzipよりも遅く7zよりも早いとのこと。拡張子は「.bz2」
LZMA データ圧縮アルゴリズム。7zやxzで利用されている。
*「xz for Java」ライブラリが追加で必要
XZ gzipやbzip2よりも高い圧縮率を誇る圧縮形式。処理速度はgzipより多少遅く、bzip2より速いとのこと。アーカイブ機能はない。
*「xz for Java」ライブラリが追加で必要
7z zipよりも高い圧縮率を持つ圧縮形式。様々な圧縮アルゴリズムに対応可能なことに加え、AES-256による暗号化も可能。
*「xz for Java」ライブラリが追加で必要
Snappy 圧縮率は低いが、処理速度が極めて速い圧縮形式。

利用方法

 Apache Commons Compressライブラリは以下のwebサイトでダウンロード可能である。必要なファイルは「commons-compress-○○.jar」であり、利用するプロジェクトのクラスパスに追加する必要がある(クラスパスの追加方法はコチラ)。版番号の遷移が分かりづらいが、最新版は1.11と思われる。


xzライブラリのコンパイル

 xzと7zを利用する場合には、上記ライブラリに加えて「xz for Java」ライブラリにもクラスパスを通す必要がある。「xz for Java」のソースは以下のwebサイトからダウンロード可能である。最新バージョンは1.5である。ライセンスはpubic domainである。


 ソースをコンパイルするにはAntを利用する。コンパイルの方法は以下のとおりである。

1.eclipse上で新規Javaプロジェクトを作成、ダウンロードしたソースを上書きコピーする。


2.「build.xml」を右クリックして「実行 - Antビルド」を実行


3.ビルドに成功すると新たに「build」フォルダが作成され、「build/jar/xz.jar」にxzライブラリが出力される。


■ サンプル・プログラム1(7z圧縮・解凍)

 以下にApache Commons Compressライブラリを利用して、7z圧縮と解凍を行うサンプル・プログラムを示す。サンプルではinputフォルダ以下のファイル群をoutput/7zfile.7zに圧縮したのち、output/7zfile.7zの内容をoutput/7zfileフォルダ以下に解凍する。

◇リソース
TestJava(プロジェクトフォルダ)
 ┣ src
 ┃ ┗ application
 ┃   ┗ TestCompress7Z.java
 ┣ input
 ┃ ┣ file1.txt
 ┃ ┣ file2.txt
 ┃ ┣ sub1
 ┃ ┃ ┗ file3.txt
 ┃ ┗ sub2
 ┗ output

◇サンプルコード
package application;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;

/**
 * 圧縮・解凍ライブラリの利用
 * Apache Commons Compressライブラリ
 * @author karura
 *
 */
public class TestCompress7Z
{
    /**
     * 起動用関数
     * @param args
     * @throws Exception 
     */
    public static void main( String[] args ) throws Exception
    {
        new TestCompress7Z();
    }
    
    /**
     * 処理メイン
     * @throws Exception
     */
    public TestCompress7Z() throws Exception
    {
        // 開始メッセージ
        System.out.println( "start!" );
        
        // ファイルの圧縮
        String      baseDir = "input";
        String[]    files   = { "file1.txt" , "file2.txt" , "sub1/file3.txt" , "sub2/"};
        
        // 7z圧縮
        compress7Z( baseDir , files , "output/7zfile.7z" );
        
        // 7z解凍
        decompress7Z( "output/7zfile.7z" , "output/7zfile/" );
        
        // 終了メッセージ
        System.out.println( "end!" );
    }
    
    /**
     * ファイルを7z圧縮する
     * @param inputBaseDir 入力ファイルを指定する際のベース・フォルダ・パス
     * @param inputFiles 圧縮するファイル名。inputBaseDirからの相対パスで指定
     * @param outputFile 作成する7zファイル名
     * @throws Exception
     */
    protected void compress7Z( String inputBaseDir , String[] inputFiles , String outputFile ) throws Exception
    {
        // 7zファイルの作成
        // try-with-resource構文でファイルcloseしている
        try(
            // 出力ファイル指定
            SevenZOutputFile        archive     = new SevenZOutputFile( new File( outputFile ) ) )
        {
            // 入力ファイルの数だけエントリーを追加
            for( String fileName : inputFiles )
            {
                // エントリー1つ分を出力開始
                File                file    = new File( fileName );

                // フォルダの場合は次へ
                if( fileName.endsWith("/") )
                { 
                    SevenZArchiveEntry  entry   = archive.createArchiveEntry( file , fileName );
                    archive.putArchiveEntry( entry );
                    entry.setDirectory(true);
                    archive.closeArchiveEntry();
                    continue;
                }
                
                // 入力ファイル指定
                SevenZArchiveEntry  entry   = archive.createArchiveEntry( file , fileName );
                archive.putArchiveEntry( entry );
                try(    FileInputStream         fis         = new FileInputStream( inputBaseDir + "/" + fileName );
                        BufferedInputStream     bis         = new BufferedInputStream( fis ))
                {
                    // エントリーの中身を出力
                    int     size    = 0;
                    byte[]  buf     = new byte[ 1024 ];
                    while( ( size = bis.read( buf ) ) > 0 )
                    {
                        archive.write( buf , 0 , size );
                    }
                }
                
                // エントリー1つ文の出力を終了
                archive.closeArchiveEntry();
            }
        }
    }
    
    /**
     * 7z解凍
     * @param inputFile 解凍するzipファイル
     * @param outputDir 解凍先フォルダ
     * @throws Exception
     */
    protected void decompress7Z( String inputFile , String outputDir ) throws Exception
    {
        // 出力先フォルダの作成
        new File( outputDir ).mkdirs();
        
        // 7zファイルの読込
        // try-with-resource構文でファイルcloseしている
        try(    SevenZFile  archive = new SevenZFile( new File( inputFile ) ) )
        {
            // エントリーを1つずつファイル・フォルダに復元
            ArchiveEntry entry   = null;
            while( ( entry = archive.getNextEntry() ) != null )
            {
                // ファイルを作成
                File    file    = new File( outputDir + "/" + entry.getName() );
                
                // フォルダ・エントリの場合はフォルダを作成して次へ
                if( entry.isDirectory() )
                {
                    file.mkdirs();
                    continue;
                }

                // ファイル出力する場合、
                // フォルダが存在しない場合は事前にフォルダ作成
                if( !file.getParentFile().exists() ){ file.getParentFile().mkdirs(); }
                
                // ファイル出力
                try(    FileOutputStream        fos = new FileOutputStream( file ) ;
                        BufferedOutputStream    bos = new BufferedOutputStream( fos ) )
                {
                    // エントリの出力
                    int     size    = 0;
                    byte[]  buf     = new byte[ 1024 ];
                    while( archive.read( buf ) > 0 )
                    {
                        bos.write( buf , 0 , size );
                    }
                }
            }
        }
    }
}
◇実行結果
 ┗ output
   ┣ 7zfile.7z
   ┗ 7zfile
     ┣ file1.txt
     ┣ file2.txt
     ┣ sub1
     ┃ ┗ file3.txt
     ┗ sub2
   
◇解説
 Apache Commons Compressライブラリを使った圧縮・解凍は、Java標準ライブラリ(java.util.zip)でzip圧縮・解凍を行う方法(詳細は別記事で紹介)と大きな差異はない。7z圧縮はcompress7Z関数(46行目)、7z解凍はdecompress7Z関数(49行目)で行っている。

 compress7Z関数内(62行目~105行目)の流れを見ると、最初にSevenZOutputFileクラスで出力ファイルを開き(68行目)、7zアーカイブに追加するエントリ(7z圧縮ファイル内のファイルのようなもの)を1つ1つ登録している(71行目~103行目)。エントリの登録はヘッダ情報であるSevenZArchiveEntryクラスを出力した後、エントリーの本文(ファイルの中身)を出力するという流れになる。

 decompress7Z関数(113行目~154行目)の内容はcompress7Z関数で行った処理の逆を行っている。


■ サンプル・プログラム2(tar.gz圧縮・解凍)

 以下にApache Commons Compressライブラリを利用して、tar.gz圧縮と解凍を行うサンプル・プログラムを示す。サンプルではinputフォルダ以下のファイル群をoutput/targzfile.tar→output/targzfile.tar.gzの順で圧縮した後、output/targzfile.tar.gzの内容をoutput/targzfile.tar→output/targzfileフォルダの順に解凍する。

◇リソース
TestJava(プロジェクトフォルダ)
 ┣ src
 ┃ ┗ application
 ┃   ┗ TestCompressTarGz.java
 ┣ input
 ┃ ┣ file1.txt
 ┃ ┣ file2.txt
 ┃ ┣ sub1
 ┃ ┃ ┗ file3.txt
 ┃ ┗ sub2
 ┗ output

◇サンプルコード
package application;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;

/**
 * 圧縮・解凍ライブラリの利用
 * Apache Commons Compressライブラリ
 * @author karura
 *
 */
public class TestCompressTarGz
{
    /**
     * 起動用関数
     * @param args
     * @throws Exception 
     */
    public static void main( String[] args ) throws Exception
    {
        new TestCompressTarGz();
    }
    
    /**
     * 処理メイン
     * @throws Exception
     */
    public TestCompressTarGz() throws Exception
    {
        // 開始メッセージ
        System.out.println( "start!" );
        
        // ファイルの圧縮
        String      baseDir = "input";
        String[]    files   = { "file1.txt" , "file2.txt" , "sub1/file3.txt" , "sub2/"};
        
        // tar圧縮
        compressTarGz( baseDir , files , "output/targzfile.tar.gz" );
        
        // tar解凍
        decompressTarGz( "output/targzfile.tar.gz" , "output/targzfile/" );
        
        // 終了メッセージ
        System.out.println( "end!" );
    }
    
    /**
     * ファイルを*.tar.gz圧縮する
     * @param inputBaseDir 入力ファイルを指定する際のベース・フォルダ・パス
     * @param inputFiles 圧縮するファイル名。inputBaseDirからの相対パスで指定
     * @param outputFile 作成する*.tar.gzファイル名
     * @throws Exception
     */
    protected void compressTarGz( String inputBaseDir , String[] inputFiles , String outputFile ) throws Exception
    {
        // tarファイル名を作成
        String outputTarFile    = outputFile.replace( ".tar.gz" , ".tar" );
        
        // tarアーカイブ作成
        try( FileOutputStream       fos  = new FileOutputStream( outputTarFile );
             TarArchiveOutputStream taos = new TarArchiveOutputStream( fos ) )
        {
            // 入力ファイルの数だけエントリーを追加
            for( String fileName : inputFiles )
            {
                // フォルダの場合は次へ
                if( fileName.endsWith("/") )
                { 
                    File             file    = new File( inputBaseDir + "/" + fileName );
                    TarArchiveEntry  entry   = new TarArchiveEntry( file , fileName );
                    taos.putArchiveEntry( entry );
                    taos.closeArchiveEntry();
                    continue;
                }
                
                // 入力ファイル指定
                File            file   = new File( inputBaseDir + "/" + fileName );
                TarArchiveEntry entry  = new TarArchiveEntry( file , fileName );
                taos.setLongFileMode( TarArchiveOutputStream.LONGFILE_POSIX );
                taos.putArchiveEntry( entry );
                try(    FileInputStream         fis         = new FileInputStream( inputBaseDir + "/" + fileName );
                        BufferedInputStream     bis         = new BufferedInputStream( fis ))
                {
                    // エントリーの中身を出力
                    int     size    = 0;
                    byte[]  buf     = new byte[ 1024 ];
                    while( ( size = bis.read( buf ) ) > 0 )
                    {
                        taos.write( buf , 0 , size );
                    }
                }
                
                // エントリー1つ文の出力を終了
                taos.closeArchiveEntry();
            }
        }
        
        // gzip圧縮
        try( FileInputStream            fis     = new FileInputStream( outputTarFile );
             BufferedInputStream        bis     = new BufferedInputStream( fis );
             FileOutputStream           fos     = new FileOutputStream( outputFile );
             GzipCompressorOutputStream archive = new GzipCompressorOutputStream(fos) )
        {
            // エントリーの中身を出力
            int     size    = 0;
            byte[]  buf     = new byte[ 1024 ];
            while( ( size = bis.read( buf ) ) > 0 )
            {
                archive.write( buf , 0 , size );
            }
        }
    }
    
    /**
     * *.tar.gz解凍
     * @param inputFile 解凍する*.tar.gzファイル
     * @param outputDir 解凍先フォルダ
     * @throws Exception 
     */
    protected void decompressTarGz( String inputFile , String outputDir ) throws Exception
    {
        // 出力先フォルダの作成
        new File( outputDir ).mkdirs();
        
        // tarファイル名を作成
        String outputTarFile    = inputFile.substring( inputFile.lastIndexOf("/" ) ).replace( ".tar.gz" , ".tar.tmp" );
        String outputTarDir     = (outputDir.endsWith("/"))? outputDir.substring( 0 , outputDir.lastIndexOf( "/" ) )
                                                           : outputDir;
               outputTarDir     = outputTarDir.substring( 0 , outputTarDir.lastIndexOf( "/" ) );
        String outputTarPath    = outputTarDir + "/" + outputTarFile;
        
        // gzip解凍
        // try-with-resource構文でファイルcloseしている
        try( FileInputStream            fis     = new FileInputStream( inputFile );
             GzipCompressorInputStream  archive = new GzipCompressorInputStream( fis );
             FileOutputStream           fos     = new FileOutputStream( outputTarPath ) )
        {
            // エントリーの中身を出力
            int     size    = 0;
            byte[]  buf     = new byte[ 1024 ];
            while( ( size = archive.read( buf ) ) > 0 )
            {
                fos.write( buf , 0 , size );
            }
        }
        
        // tarアーカイブ解除
        // try-with-resource構文でファイルcloseしている
        try( FileInputStream       fis  = new FileInputStream( outputTarPath );
             TarArchiveInputStream tais = new TarArchiveInputStream( fis ) )
        {
            // エントリーを1つずつファイル・フォルダに復元
            ArchiveEntry entry   = null;
            while( ( entry = tais.getNextEntry() ) != null )
            {
                // ファイルを作成
                File    file    = new File( outputDir + "/" + entry.getName() );
                
                // フォルダ・エントリの場合はフォルダを作成して次へ
                if( entry.isDirectory() )
                {
                    file.mkdirs();
                    continue;
                }

                // ファイル出力する場合、
                // フォルダが存在しない場合は事前にフォルダ作成
                if( !file.getParentFile().exists() ){ file.getParentFile().mkdirs(); }
                
                // ファイル出力
                try(    FileOutputStream        fos = new FileOutputStream( file ) ;
                        BufferedOutputStream    bos = new BufferedOutputStream( fos ) )
                {
                    // エントリの出力
                    int     size    = 0;
                    byte[]  buf     = new byte[ 1024 ];
                    while( tais.read( buf ) > 0 )
                    {
                        bos.write( buf , 0 , size );
                    }
                }
            }
        }
        
    }
    
}
◇実行結果
 ┗ output
   ┣ targzfile.tar
   ┣ targzfile.tar.gz
   ┣ targzfile.tar.tmp
   ┗ targzfile
     ┣ file1.txt
     ┣ file2.txt
     ┣ sub1
     ┃ ┗ file3.txt
     ┗ sub2

◇解説
 tar.gz圧縮・解凍と7z圧縮・解凍の大きな違いは、tar.gz圧縮・解凍が2段階の処理を行う点である。これはtarがアーカイブ機能(複数ファイルを1ファイルにまとめる)しか持たず、gzipが1ファイルに対する圧縮・解凍機能しか持たないことに由来する。

 tarアーカイブ処理はzipや7zの圧縮処理と同様の処理と流れとなり、TarArchiveOutputStreamに対してエントリのヘッダ情報(TarArchiveEntryクラス)とエントリの本文を登録していくという流れになる(70行目~106行目)。tarアーカイブ解除については、その逆の処理である(159行目~193行目)。

 gz圧縮・解凍は簡単で、GzipCompressorOutputStreamクラスおよびGzipCompressorInputStreamクラスでファイルを入出力するだけでよい(108行目~121行目、142行目~155行目)。

■ 参照

  1. Apache Commons Compress 「Examples」
  2. Apache Commons Compress 1.11 API
  3. programcreek 「Java Code Examples for org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream」
- PR -
Home > Java > Java 圧縮・解凍ライブラリによる7z/tar.gz等の利用(Apache Commons Compress)

- ランダム記事 -

コメント

ただいまコメントを受けつけておりません。

QRコード

プロフィール

管理者:
連絡はContactよりお願いします。

PR