【Java】Tar、GZを読み込む

Linux標準の圧縮形式、tar.gz。業務で、Javaの小物を作ることになったのでメモ。

tar.gzの仕組み

2段階に圧縮している。

ファイル
  |
(複数ファイルをTARで1つのバイナリに連結)
  ↓
TARファイル
  |
(1ファイルをGZip圧縮)
  ↓
TAR.GZファイル

Javaのライブラリ

今回は、Java標準のGZIPInputStreamApache Commons CompressのTarArchiveInputStreamを使った。

File outDir = new File("/outdir");
File gzipFile = new File("sample.tar.gz");

try (FileInputStream fis = new FileInputStream(gzipFile)) {
    try (GZIPInputStream gis = new GZIPInputStream(fis)) {
        try (TarArchiveInputStream tis = new TarArchiveInputStream(gis)) {
            for (AchiveEntry entry = tis.getNextEntry(); entry != null; entry = tis.getNextEntry()) {
                if (entry.isDirectory()) {
                    File newDir = new File(outDir, entry.getName());
                    if (!newDir.mkdirs()) {
                        throw new IOException("directory " + newDir.getAbsolutePath() + " cannot create.');
                    }
                } else {
                    File newfile = new File(outDir, entry.getName());
                    File parentDir = newfile.getParent();
                    if (!parentDir.mkdirs()) {
                        throw new IOException("directory " + parentDir.getAbsolutePath() + " cannot create.');
                    }
                    try (FileOutputStream fos = new FileOutputStream(newfile)) {
                        IOUtils.copy(tis, fos);  // Apache common-io
                    }
                }
            }
        }
    }
}

なんだこのネスト。やってることは単純なんだけど。

TarAchiveInputStreamのAPIがやや癖があって、getNextEntryすると、TarArhiveInputStreamのファイルポインタが進む。

また、GZIPInputStreamには作業バッファ長が与えられる。だいたい、デフォルトの8196で十分だが、CPUリソースが余りに余るようであれば増やしてもよいかもしれない。