2014年7月2日水曜日

javaでzipファイルを作成する

javaでzipな要件が出てきたのでちょっと書いてみました。

javaに関してはド素人なので文法やお約束などすっとばしてる可能性大ですがご容赦ください。


【やること】

・zipファイル名、対象のファイル、格納する際のパス加工を指定してzip処理を行う。
・元のファイルは特にいじらない。
・ディレクトリ指定された場合、ディレクトリ内のすべてのファイルを対象とする。


【実施環境】

CentOS6.5
java version "1.6.0_30"
OpenJDK Runtime Environment (IcedTea6 1.13.3) (rhel-5.1.13.3.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)


【注意点】

いろんな情報を見ていると、JRE1.6系では全角のファイル名が扱えないとか
何とか、いろんな情報が出ているようです。
その為の検証だったのですが、結果、問題ありませんでした。
⇒その後の検証で原因発覚。利用している解凍ツールが対応していただけでした。


ant.jarが持つ、Zip圧縮ツールを使うサンプルです。

【ソースの中身でちょっと分かりづらい仕様の説明】

・存在しないファイルを指定した場合、ゴミZipだけが残る事象が確認されたため
 回避するためにNotFoundExceptionを発生させています。
・絶対パス指定の場合、私の環境ではきれいにフォルダ構成まで作られてしまったため
 それを回避するためにZipEntryへは相対パス以下のフォルダ指定をするようにしました。
・ライブラリを、java.io.zipへ戻せるように、Encodingは外から指定可能とし、
 指定された場合のみ使うようにしました。



【ソース】


汎用性を持たせるため、2つに分けました。

----------------------------------------------------------------
ZipTest.java
----------------------------------------------------------------

import java.io.*;
import java.lang.*;
import java.util.*;
import java.util.ArrayList;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

public class ZipTest{
  public static void main(String[] args){
    File  file;                 //作成するzipファイルの名前
    List<File> files = new ArrayList<File>();
    String baseDirectory = "";
    if (args != null && args.length > 2)
    {
      //引数1 zipファイル名
      file = new File(args[0]);
       
      //引数2 基準ディレクトリ
      baseDirectory = args[1];

      //引数3以降 対象ファイルのパス
      for (int i= 2;i<args.length;i++)
      {
        files.add(new File(args[i]));
      }
      System.out.println(files.size());
    }
    else
    {
      //demo
      file = new File("sample.zip");
      baseDirectory = "/tmp/sample/csv/";
      //圧縮対象を相対パスで指定
      files.add(new File("/tmp/sample/csv/あ.txt"));
      files.add(new File("/tmp/sample/csv/い.txt"));
      files.add(new File("/tmp/sample/csv/ああ.txt"));
      files.add(new File("/tmp/sample/csv/いい.txt"));
    }

    ZipCompressUtils zip;
    zip = new ZipCompressUtils(baseDirectory);

    try{
      zip.Compress(file,files);
    }
    catch (Exception e){
    }
  }
}

----------------------------------------------------------------


実行処理
----------------------------------------------------------------
ZipCompressUtils.java
----------------------------------------------------------------


import java.io.*;
import java.lang.*;
import java.util.*;
//import java.util.zip.ZipEntry;
//import java.util.zip.ZipOutputStream;
import org.apache.tools.zip.*;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;

public class ZipCompressUtils
{
  //Private Declare
  static String _rootPath = null;
  static String _encoding = "MS932";
   
  //Constructor
  public ZipCompressUtils()
  {
  }
  public ZipCompressUtils(String rootPath)
  {
    _rootPath = rootPath;
  }
  public ZipCompressUtils(String rootPath , String encoding)
  {
    _rootPath = rootPath;
    _encoding = encoding;
  }
  public boolean Compress(File target , List<File> files) throws Exception {
    try{
      ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(target));
     encode(zos, files);
      if (_encoding != null)
      {
        zos.setEncoding(_encoding);
      }
     zos.close();
      return true;
    }
    catch (Exception e){
      target.delete();
      throw e;
    }
  }
  static void encode(ZipOutputStream zos, List<File> files) throws Exception {
    byte[] buf = new byte[1024];

    //File配列のLoop
    for (File f : files) {
      if (!(f.exists())){
        throw new FileNotFoundException();
      }
      //ディレクトリなら再帰
      if (f.isDirectory()) {
        encode(zos, Arrays.asList(f.listFiles()));
      } else {
        //ファイルの場合の処理
        String zipEntryPath = f.getPath().replace(_rootPath,"").toString().replace("\\", "/");
        ZipEntry entry = new ZipEntry(zipEntryPath);
        zos.putNextEntry(entry);
        InputStream is = new BufferedInputStream(new FileInputStream(f));
        for (;;) 
        {
          int len = is.read(buf);
          if (len < 0) break;
          zos.write(buf, 0, len);
        }
      }
    }
  }
}

0 件のコメント: