Java Tips | I/O・ネットワーク:gzip圧縮

Java Java
スポンサーリンク

gzip圧縮ユーティリティは何のために必要なのか

業務システムでは、ログ、CSV、JSON、バックアップファイルなど「サイズが大きくなりがちなデータ」を扱う場面が多くあります。 そのまま保存するとディスクを圧迫し、ネットワーク転送にも時間がかかります。 そこで役に立つのが gzip圧縮 です。

gzipは「高速・軽量・広く使われている」圧縮方式で、Java 標準ライブラリだけで簡単に扱えます。 初心者がつまずきやすいポイントは、 「ストリームをどうつなぐか」「どこで閉じるか」「バイトと文字列の境界をどう扱うか」 といった部分です。

ここから、実務で使える形に噛み砕いて解説します。

gzip圧縮の基本:GZIPOutputStream を使う

圧縮したいデータを OutputStream に流すだけ

Java では、gzip圧縮は GZIPOutputStream を使うだけで実現できます。 「OutputStream に流したデータが gzip 形式で書き出される」という仕組みです。

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPOutputStream;

public class GzipUtils {

    public static void compress(Path input, Path output) throws IOException {
        try (OutputStream out = new GZIPOutputStream(Files.newOutputStream(output))) {
            byte[] bytes = Files.readAllBytes(input);
            out.write(bytes);
        }
    }
}
Java

使い方の例です。

Path input  = Path.of("data/report.csv");
Path output = Path.of("data/report.csv.gz");

GzipUtils.compress(input, output);
Java

ここで深掘りしたいポイントは 「GZIPOutputStream は OutputStream の一種」 ということです。 つまり、OutputStream out = new GZIPOutputStream(...) としておけば、 out.write() に流したバイトが自動的に gzip 形式に変換されます。

gzip解凍の基本:GZIPInputStream を使う

圧縮されたデータを InputStream から読み出すだけ

解凍は GZIPInputStream を使います。 「InputStream から読み出したデータが自動的に解凍される」という仕組みです。

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 input, Path output) throws IOException {
        try (InputStream in = new GZIPInputStream(Files.newInputStream(input))) {
            byte[] bytes = in.readAllBytes();
            Files.write(output, bytes);
        }
    }
}
Java

使い方の例です。

Path input  = Path.of("data/report.csv.gz");
Path output = Path.of("data/report.csv");

GzipUtils.decompress(input, output);
Java

ここで深掘りしたいポイントは 「GZIPInputStream は InputStream の一種」 ということです。 つまり、in.read() で読み出したバイトはすでに解凍済みです。

ストリームコピーと組み合わせると強力になる

大きなファイルは「readAllBytes」ではなくストリームで流す

先ほどの例はシンプルですが、巨大ファイルでは readAllBytes() がメモリを圧迫します。 そこで、gzip圧縮とストリームコピーを組み合わせます。

import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.zip.GZIPOutputStream;

public class GzipStreamUtils {

    public static void compressStream(Path input, Path output) throws Exception {
        try (InputStream in = Files.newInputStream(input);
             OutputStream out = new GZIPOutputStream(Files.newOutputStream(output))) {

            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
        }
    }
}
Java

ここで深掘りしたいポイントは 「部分読み込みと部分書き込み」 です。

in.read(buffer) は「バッファサイズぴったり読める」とは限らず、 実際に読めたバイト数(len)を返します。

必ず out.write(buffer, 0, len) として「有効な範囲だけ」書き出す必要があります。 これを怠ると、gzipファイルが壊れます。

gzip圧縮と文字列の扱い

テキストを圧縮するときは「文字コード」を必ず指定する

CSV や JSON を gzip圧縮する場合、 「文字列 → バイト列 → gzip」という流れになります。

String text = "こんにちは、MONOさん!";
byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
Java

ここで深掘りしたいポイントは 「文字コードを必ず指定する」 ことです。 getBytes() を文字コードなしで呼ぶと、環境依存になり、 本番と検証環境で結果が変わる危険があります。

gzip圧縮の実務的な使いどころ

ログ・CSV・JSON の圧縮保存

ログやCSVはサイズが大きくなりがちなので、 「保存時に gzip圧縮する」だけでディスク使用量を大幅に削減できます。

HTTPレスポンスの gzip圧縮(Web API)

Web API では、レスポンスを gzip圧縮して返すことで通信量を減らせます。 Java の Web フレームワークは多くが自動対応していますが、 自前でやる場合は GZIPOutputStream を使います。

バックアップファイルの圧縮

設定ファイルやデータファイルをバックアップするとき、 gzip圧縮しておくと保存容量が減り、転送も高速になります。

セキュリティ・運用の観点から見た gzip圧縮

圧縮ファイルの「展開先」を必ず制御する

gzip解凍は「展開先のパス」を指定する必要があります。 外部入力からパスをそのまま受け取ると、 ディレクトリトラバーサル攻撃(../../etc/passwd)の危険があります。

必ず「許可されたディレクトリ配下に限定する」設計にしてください。

圧縮ファイルのサイズに注意する(ZIP爆弾)

gzipはZIPほど危険ではありませんが、 「圧縮前は巨大なデータ」を送りつける攻撃は存在します。

解凍前にサイズチェックを行う、 ストリームで少しずつ処理する、 といった対策が有効です。

まとめ:gzip圧縮ユーティリティで身につけてほしい感覚

gzip圧縮ユーティリティは、 「バイト列を効率よく圧縮・解凍する」ための小さな道具です。

その裏には次のような大事なポイントがあります。

GZIPOutputStream を使えば、書き込むだけで自動圧縮される。 GZIPInputStream を使えば、読み出すだけで自動解凍される。 巨大ファイルは ストリームコピー と組み合わせる。 文字列を圧縮する場合は UTF-8 を必ず指定する。 解凍時のパス制御やサイズチェックなど、セキュリティも意識する。

もしあなたのプロジェクトで、 「CSVをそのまま保存してディスクが圧迫されている」 「ログが巨大化して困っている」 「APIレスポンスが重い」 といった課題があるなら、gzip圧縮ユーティリティを導入する価値があります。

タイトルとURLをコピーしました