AntAPIの"tar"と"bzip2"で圧縮&解凍
「Javaでアーカイバ(java.util.zip関連) - argius note」のAntAPIから派生。
AntAPIには、前述エントリで使った"org.apache.tools.zip.*"の他に、"tar","bzip2"があります。GZIPが無いのは、標準APIで良いということのようです。
使ってみたので、サンプルを置いておきます。使っているAntのバージョンは、ちょっと古めの"1.6.5"です。
生成されたファイルの確認に使用したツールは、LhazとCygwinコマンド(tar,gzip,bzip2)です。
また、準備として、以下の共通メソッドとインポートを示します。"ant.jar"をクラスパスに追加するのを忘れないようにしてください。
import java.io.*; import java.util.zip.*; import org.apache.tools.bzip2.*; import org.apache.tools.tar.*; static void transfer(InputStream is, OutputStream os) throws IOException { byte[] buffer = new byte[8192]; // 何故8192なのでしょうか for (int readLength; (readLength = is.read(buffer)) >= 0;) { os.write(buffer, 0, readLength); } os.flush(); }
Tar日本語対応
ZIPはエンコーディングが指定できるのに、Tarはできません。
日本語ファイル名を使えるようにするには、以下の暫定パッチを使います。あくまで暫定なので注意。Windows以外でどうなるかは試してません。
SVN"ANT_165 278395"タグのパッチです。
Index: src/main/org/apache/tools/tar/TarUtils.java =================================================================== --- src/main/org/apache/tools/tar/TarUtils.java (revision 705959) +++ src/main/org/apache/tools/tar/TarUtils.java (working copy) @@ -76,6 +76,7 @@ StringBuffer result = new StringBuffer(length); int end = offset + length; + int size = 0; for (int i = offset; i < end; ++i) { if (header[i] == 0) { break; @@ -81,8 +82,9 @@ break; } - result.append((char) header[i]); + ++size; } + result.append(new String(header, offset, size)); return result; } @@ -98,8 +100,9 @@ public static int getNameBytes(StringBuffer name, byte[] buf, int offset, int length) { int i; - for (i = 0; i < length && i < name.length(); ++i) { - buf[offset + i] = (byte) name.charAt(i); + byte[] bytes = name.toString().getBytes(); // default encoding + for (i = 0; i < length && i < bytes.length; ++i) { + buf[offset + i] = bytes[i]; } for (; i < length; ++i) {
Tar+Gzip形式
カレントディレクトリには、"dir/a.txt","dir/b.bin"があります。
Tarだけにしたい場合は、GZIPストリームを外すだけです。
// write tar+gz File srcdir = new File("dir/"); File dstfile = new File("test.tar.gz"); TarOutputStream tos = new TarOutputStream(new GZIPOutputStream(new FileOutputStream(dstfile))); try { for (File file : srcdir.listFiles()) { TarEntry entry = new TarEntry(file); /* * // Fileオブジェクトを使わない場合 * TarEntry entry = new TarEntry(entryName); * entry.setSize(length); * entry.setModTime(lastModifiedTime); */ tos.putNextEntry(entry); InputStream is = new FileInputStream(file); try { transfer(is, tos); } finally { is.close(); } tos.closeEntry(); } } finally { tos.close(); }
// read tar+gz File srcfile = new File("test.tar.gz"); TarInputStream tis = new TarInputStream(new GZIPInputStream(new FileInputStream(srcfile))); try { for (TarEntry entry; (entry = tis.getNextEntry()) != null;) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); transfer(tis, bos); System.out.printf("%s : %s%n", entry.getName(), new String(bos.toByteArray())); } } finally { tis.close(); }
Bzip2形式
GZIP系と同じと思いきや、ちょっとだけ面倒です。先頭のIDを自分でつけてあげないといけないようです。この辺の事情は知りません。
読み込みの方は省略します。tar+bzip2にしたい場合は、tar+gzip版のGZIPをこれに置き換えてください。単純に置き換えだけで済まないのが厄介ですが.....
// write File srcfile = new File("dir", "a.txt"); File dstfile = new File("./", srcfile.getName() + ".bz2"); FileOutputStream fos = new FileOutputStream(dstfile); try { fos.write(new byte[]{(byte)0x42, (byte)0x5A}); // id=BZ // blockSize指定もできる CBZip2OutputStream(OutputStream os, int blockSize) CBZip2OutputStream os = new CBZip2OutputStream(fos); try { InputStream is = new FileInputStream(srcfile); try { transfer(is, os); } finally { is.close(); } } finally { os.close(); } } finally { fos.close(); }