業務で「tar対応」ユーティリティが必要になる場面
ZIP は Windows 文化、tar は Unix/Linux 文化——そんなイメージがあります。 業務システムでも、サーバーが Linux だったり、外部システムから .tar や .tar.gz が送られてきたりすると、「tar を読めないと仕事にならない」場面が普通に出てきます。
Java 標準ライブラリには tar サポートがないので、 実務では「ライブラリを使って tar を扱うユーティリティ」を用意しておくのが定番です。 ここでは、代表的なライブラリを前提に、「tar対応」を初心者向けに噛み砕いて説明します。
tarとは何か、ZIPとの違いをざっくり押さえる
tarは「圧縮しないアーカイブ」、gzipと組み合わせて使われる
tarは「複数ファイルをひとまとめにするフォーマット」で、 それ自体には圧縮機能がありません。
backup.tar は「ただの束ねたファイルの塊」、 backup.tar.gz は「tarで束ねたものをgzipで圧縮したもの」です。
ZIPは「まとめる+圧縮」を一体でやりますが、 tarは「まとめる」と「圧縮する」を分けて考える——ここが大きな違いです。
代表的なライブラリでの「tar展開」ユーティリティのイメージ
※ここでは、Apache Commons Compress のような「tarを扱えるライブラリ」がある前提で話します。
tarをディレクトリに展開する基本形
tar対応のライブラリは、だいたい「TarArchiveInputStream」のようなクラスを提供します。 ZIPのときと同じく、「エントリを順番に読みながら展開する」スタイルです。
イメージとしては、こんな感じになります。
public class TarExtractUtils {
public static void extractTar(InputStream tarIn, Path targetDir) throws IOException {
try (TarArchiveInputStream in = new TarArchiveInputStream(tarIn)) {
TarArchiveEntry entry;
while ((entry = in.getNextTarEntry()) != null) {
if (entry.isDirectory()) {
Path dir = targetDir.resolve(entry.getName());
Files.createDirectories(dir);
} else {
Path file = targetDir.resolve(entry.getName());
Files.createDirectories(file.getParent());
try (OutputStream out = Files.newOutputStream(file)) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
}
}
}
}
}
JavaZIP解凍とほぼ同じ構造ですが、クラス名やメソッド名が tar 用になっているだけです。 「エントリを順番に取り出して、ディレクトリなら作る、ファイルなら中身を書き出す」という流れが共通パターンになります。
tar.gz(圧縮付き)を扱うときのストリームの重ね方
gzip解凍 → tar展開、という二段構えのストリーム
.tar.gz を扱うときは、「まず gzip を解凍して、その中身を tar として読む」という二段構えになります。
ストリームの重ね方はこうです。
InputStream fileIn = Files.newInputStream(pathToTarGz);
InputStream gzipIn = new GZIPInputStream(fileIn);
TarArchiveInputStream tarIn = new TarArchiveInputStream(gzipIn);
Javaこのように、「外側から順にラップしていく」イメージです。
あとは先ほどの extractTar と同じように、 tarIn.getNextTarEntry() を回しながら展開していきます。
ここで深掘りしたいポイントは、「ストリームの責務を分けて考える」ことです。
gzipは「圧縮を解く」役割、 tarは「束ねられたファイルを一つずつ取り出す」役割。
それぞれのストリームが何をしているかを意識できると、 バグが減るだけでなく、ログや監査の観点でも説明しやすくなります。
パスの扱いとディレクトリトラバーサル対策(tarでも必須)
entry.getName() をそのまま信じない、という姿勢
tarのエントリ名にも、../ を含む相対パスが入っている可能性があります。 ZIPと同じく、「展開先のベースディレクトリからはみ出さないようにする」チェックが重要です。
イメージとしては、次のようなヘルパーを用意します。
private static Path safeResolve(Path baseDir, String entryName) throws IOException {
Path target = baseDir.resolve(entryName).normalize();
if (!target.startsWith(baseDir.normalize())) {
throw new IOException("不正なパスです: " + entryName);
}
return target;
}
Java展開時には必ずこれを通してからファイルパスを決めます。
tarは「Unix文化のツールだから安全」とは限りません。 外部から渡される tar を扱う以上、ZIPと同じくディレクトリトラバーサル対策は必須です。
tar対応ユーティリティの実務的な使いどころ
Linuxサーバーとの連携・バックアップ・ログ収集
Linux系のツールや運用フローでは、 バックアップやログ収集に tar がよく使われます。
例えば、
- サーバー側で
tarコマンドで固めたファイルを、Java側で受け取って展開する - 外部システムから
.tar.gzで渡されるデータをインポートする - Javaで生成したファイル群を tar にして、別の Unix系システムに渡す
といった場面で、「tar対応ユーティリティ」があるかどうかが効いてきます。
まとめ:tar対応ユーティリティで身につけてほしい感覚
tar対応ユーティリティは、「Unix文化のアーカイブ形式を、Javaから自然に扱う」ための橋渡しです。 そこには、次のような感覚が詰まっています。
tarは「まとめる」、gzipは「圧縮する」——役割を分けて理解する。 tar展開は、ZIPと同じく「エントリを順番に読みながらディレクトリとファイルを作る」構造を持つ。 .tar.gz はストリームを重ねて、gzip解凍 → tar展開の二段構えで扱う。 エントリ名を正規化し、ベースディレクトリからはみ出さないようにしてディレクトリトラバーサルを防ぐ。
もしあなたの現場で、 「Linux側から tar で渡されるファイルを手作業で展開している」 「Java側で tar を扱えず、運用が歪んでいる」 という状況があるなら、 この tar対応ユーティリティを軸に、JavaとUnix文化の間のギャップを埋めていくのがいいタイミングです。
