なぜ「gzip解凍ユーティリティ」が業務で必須になるのか
業務システムでは、ログ、CSV、JSON、バックアップファイルなどを gzip で圧縮して保存・転送することがよくあります。 その結果、「読むときは必ず gzip を解凍する」という処理が、あちこちに散らばりがちになります。
毎回その場で GZIPInputStream を直接書いていると、 ストリームの閉じ忘れ、例外処理のバラつき、文字コードの扱いミスなどが起きやすくなります。 だからこそ、「gzip解凍」を小さなユーティリティとしてまとめておくと、業務コードがすっきりし、バグも減ります。
基本形:gzipファイルを丸ごと解凍して別ファイルに書き出す
GZIPInputStream と Files.write を組み合わせる
まずは一番分かりやすい、「xxx.gz を解凍して元のファイルを作る」ユーティリティから押さえましょう。
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
public class GzipUtils {
public static void decompress(Path inputGzip, Path outputFile) throws IOException {
try (InputStream in = new GZIPInputStream(Files.newInputStream(inputGzip))) {
byte[] bytes = in.readAllBytes();
Files.write(outputFile, bytes);
}
}
}
Java使い方の例です。
import java.nio.file.Path;
public class DecompressExample {
public static void main(String[] args) throws Exception {
Path input = Path.of("data/report.csv.gz");
Path output = Path.of("data/report.csv");
GzipUtils.decompress(input, output);
}
}
Javaここで重要なのは、「GZIPInputStream は普通の InputStream と同じように扱える」ということです。 new GZIPInputStream(...) でラップした瞬間、read() で読み出されるバイトはすでに解凍済みになります。
もう一つのポイントは、try-with-resources でストリームを必ず閉じていることです。 解凍処理は I/O を伴うので、ストリームを閉じ忘れるとファイルハンドルが枯渇し、長期運用で障害につながります。
大きなファイルを「ストリームで解凍」する形
readAllBytes を避けて、少しずつ読みながら書き出す
先ほどの例はシンプルですが、巨大な gzip ファイルでは readAllBytes() がメモリを圧迫します。 そこで、「少しずつ読みながら書き出す」ストリーム解凍ユーティリティを用意します。
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
public class GzipStreamUtils {
public static void decompressStream(Path inputGzip, Path outputFile) throws IOException {
try (InputStream in = new GZIPInputStream(Files.newInputStream(inputGzip));
OutputStream out = Files.newOutputStream(outputFile)) {
byte[] buffer = new byte[8192];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}
}
}
Javaここで深掘りしたいのは、「部分読み込みと部分書き込み」の扱いです。 in.read(buffer) は、バッファサイズぴったり読めるとは限らず、「今回実際に読めたバイト数」を返します。 必ず out.write(buffer, 0, len) として、「有効な範囲だけ」書き出す必要があります。 これを怠ると、解凍されたファイルにゴミが混ざり、データが壊れます。
gzip解凍したデータをそのままメモリで扱うユーティリティ
「解凍して byte[] を返す」形
ファイルに書き出さず、「解凍した中身をメモリでそのまま扱いたい」場面もあります。 例えば、gzip圧縮された JSON を解凍して、そのままパースしたい場合です。
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPInputStream;
public class GzipMemoryUtils {
public static byte[] decompressToBytes(Path inputGzip) throws IOException {
try (InputStream in = new GZIPInputStream(Files.newInputStream(inputGzip))) {
return in.readAllBytes();
}
}
}
Java使い方の例です。
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
public class DecompressToBytesExample {
public static void main(String[] args) throws Exception {
Path input = Path.of("data/data.json.gz");
byte[] bytes = GzipMemoryUtils.decompressToBytes(input);
String json = new String(bytes, StandardCharsets.UTF_8);
System.out.println(json);
}
}
Javaここで重要なのは、「文字列にするときは必ず文字コードを指定する」ことです。 new String(bytes) とすると環境依存になり、文字化けや本番との挙動差の原因になります。 業務システムでは、ほぼ常に UTF-8 に統一するのがおすすめです。
gzip解凍とセキュリティ・運用の観点
展開先パスを必ず制御する
解凍ユーティリティは「どこに書き出すか」を決める必要があります。 外部入力からパスをそのまま受け取ると、 ../../ を使ったディレクトリトラバーサル攻撃で、意図しない場所にファイルを書かれる危険があります。
実務では、次のような方針を取るのが安全です。
アプリケーションが書いてよいベースディレクトリを決める。 ユーティリティは、その配下にしか書き出さないようにする。 ファイル名は外部入力から受け取っても、ディレクトリは固定する。
こうしておくと、「gzip解凍ユーティリティがどこに何を書いているか」が明確になり、監査や運用の観点でも安心できます。
解凍前にサイズや拡張子をチェックする
gzipファイルは、圧縮前のサイズが非常に大きい場合があります。 悪意ある入力(いわゆる“圧縮爆弾”)を解凍すると、ディスクやメモリを一気に消費してしまうことがあります。
実務では、次のような対策が有効です。
アップロードされた gzip ファイルのサイズ上限を決める。 解凍先のディスク容量を監視し、閾値を超えたら警告・停止する。 用途に応じて拡張子(.gz)や MIME タイプをチェックする。
ユーティリティ単体ではなく、運用設計とセットで考えることで、 gzip解凍を安全に業務フローに組み込めます。
まとめ:gzip解凍ユーティリティで身につけてほしい感覚
gzip解凍ユーティリティは、「圧縮されたデータを安全に元に戻す」ための小さな道具ですが、 その裏には次のような大事なポイントが詰まっています。
GZIPInputStream は「解凍済みバイトを返す InputStream」である。 小さなデータは readAllBytes、大きなデータはバッファを使ったストリーム解凍にする。 ストリームは try-with-resources で必ず閉じ、リソースリークを防ぐ。 解凍したテキストを扱うときは、文字コード(UTF-8など)を必ず指定する。 展開先パスやサイズ上限など、セキュリティ・運用のルールとセットで設計する。
もしあなたのプロジェクトで、 あちこちにバラバラな GZIPInputStream のコードが散らばっているなら、 それを一度「業務用 gzip解凍ユーティリティ」にまとめられないか眺めてみてください。
そこから先は、圧縮データの扱いがぐっと安定し、 ログ・CSV・JSON・バックアップなど、サイズの大きなデータを安心して運用できるようになっていきます。
