Node.js zlib モジュール

Node.js組み込みモジュール


zlib は Node.js に組み込まれたコアモジュールで、データ圧縮と解凍機能を提供します。広く使用されている圧縮ライブラリである zlib ライブラリに基づいており、次のような複数の圧縮形式をサポートしています:

  • Gzip:最も一般的な圧縮形式
  • Deflate:もう一つの人気のある圧縮アルゴリズム
  • Brotli:Google が開発した新しい圧縮アルゴリズム

データ圧縮が必要な理由

ネットワーク転送やファイル保存において、データ圧縮には以下のような利点があります:

  1. 帯域幅の消費を削減:圧縮後のデータはサイズが小さくなり、転送が高速化します
  2. 保存容量を節約:圧縮ファイルはディスク容量をより少なく使用します
  3. パフォーマンスの向上:圧縮・解凍には CPU リソースが必要ですが、通常ネットワーク I/O の節約の方が顕著です

基本的な使用方法

データの圧縮

例

const zlib = require('zlib');
const fs = require('fs');

// 読み取りストリームを作成
const input = fs.createReadStream('input.txt');

// Gzip 圧縮ストリームを作成
const gzip = zlib.createGzip();

// 書き込みストリームを作成
const output = fs.createWriteStream('input.txt.gz');

// パイプライン接続:読み取り -> 圧縮 -> 書き込み
input.pipe(gzip).pipe(output);

データの解凍

例

const zlib = require('zlib');
const fs = require('fs');

// 読み取りストリームを作成(圧縮ファイル)
const input = fs.createReadStream('input.txt.gz');

// Gunzip 解凍ストリームを作成
const gunzip = zlib.createGunzip();

// 書き込みストリームを作成
const output = fs.createWriteStream('input.txt');

// パイプライン接続:読み取り -> 解凍 -> 書き込み
input.pipe(gunzip).pipe(output);

圧縮メソッドの詳細

zlib モジュールは、さまざまなシーンに適した複数の圧縮メソッドを提供しています:

同期メソッド

少量のデータの処理に適しており、操作は簡単ですがイベントループをブロックします:

例

const zlib = require('zlib');
const input = '圧縮が必要なテキストデータ';

// 同期圧縮
const compressed = zlib.deflateSync(input);
console.log('圧縮後:', compressed.toString('base64'));

// 同期解凍
const decompressed = zlib.inflateSync(compressed);
console.log('解凍後:', decompressed.toString());

非同期メソッド

大量のデータの処理に適しており、イベントループをブロックしません:

例

const zlib = require('zlib');
const input = '圧縮が必要なテキストデータ';

// 非同期圧縮
zlib.deflate(input, (err, compressed) => {
  if (!err) {
    console.log('圧縮後:', compressed.toString('base64'));
   
    // 非同期解凍
    zlib.inflate(compressed, (err, decompressed) => {
      if (!err) {
        console.log('解凍後:', decompressed.toString());
      }
    });
  }
});

ストリーム処理

大きなファイルやネットワークデータの処理に最も適しており、メモリ効率が高いです:

例

const zlib = require('zlib');
const fs = require('fs');

// 変換ストリームを作成
const gzip = zlib.createGzip({
  level: zlib.constants.Z_BEST_COMPRESSION // 最高圧縮レベル
});

fs.createReadStream('largefile.txt')
  .pipe(gzip)
  .pipe(fs.createWriteStream('largefile.txt.gz'))
  .on('finish', () => console.log('圧縮完了'));

高度な設定オプション

zlib の圧縮メソッドは設定オブジェクトを受け取って、圧縮動作をカスタマイズできます:

一般的な設定パラメータ

例

{
  level: zlib.constants.Z_DEFAULT_COMPRESSION, // 圧縮レベル
  memLevel: 8,                                // メモリ使用レベル
  strategy: zlib.constants.Z_DEFAULT_STRATEGY, // 圧縮ストラテジー
  windowBits: 15,                             // ウィンドウサイズ
  chunkSize: 16 * 1024,                       // ブロックサイズ
  dictionary: null                            // プリセット辞書
}

圧縮レベルの説明

レベル定数 值 説明
Z_NO_COMPRESSION 0 圧縮しない
Z_BEST_SPEED 1 最速、最低圧縮率
Z_BEST_COMPRESSION 9 最高圧縮率、最遅速度
Z_DEFAULT_COMPRESSION -1 デフォルトのバランス方式 (通常=6)

実際の適用シーン

HTTPレスポンスの圧縮

Webサーバーで HTTPレスポンスを圧縮すると、転送データ量を大幅に削減できます:

例

const http = require('http');
const zlib = require('zlib');

http.createServer((req, res) => {
  const responseText = 'これは圧縮が必要なレスポンステキストです'.repeat(100);
 
  // クライアントが gzip 圧縮を受け付けるかどうかを確認
  if (req.headers['accept-encoding'] && req.headers['accept-encoding'].includes('gzip')) {
    res.writeHead(200, {
      'Content-Encoding': 'gzip',
      'Content-Type': 'text/plain'
    });
    zlib.gzip(responseText, (err, compressed) => {
      res.end(compressed);
    });
  } else {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(responseText);
  }
}).listen(3000);

ファイル圧縮アーカイブ

複数のファイルを一括圧縮:

例

const zlib = require('zlib');
const fs = require('fs');
const path = require('path');
const { pipeline } = require('stream');

const files = ['file1.txt', 'file2.txt', 'file3.txt'];

files.forEach(file => {
  const input = fs.createReadStream(file);
  const output = fs.createWriteStream(`${file}.gz`);
 
  pipeline(
    input,
    zlib.createGzip(),
    output,
    (err) => {
      if (err) console.error(`圧縮 ${file}失敗:`, err);
      else console.log(`成功圧縮 ${file}`);
    }
  );
});

データベース保存の最適化

大型の JSON データを圧縮して保存:

例

const zlib = require('zlib');
const fs = require('fs');

const largeData = {
  /* 大型 JSON オブジェクト */
};

// 圧縮して保存
zlib.deflate(JSON.stringify(largeData), (err, compressed) => {
  if (!err) {
    fs.writeFile('data.json.deflate', compressed, (err) => {
      if (!err) console.log('データ圧縮保存成功');
    });
  }
});

// 読み取り時に解凍
fs.readFile('data.json.deflate', (err, data) => {
  if (!err) {
    zlib.inflate(data, (err, decompressed) => {
      if (!err) {
        const originalData = JSON.parse(decompressed.toString());
        console.log('データ復元成功');
      }
    });
  }
});

パフォーマンス最適化のアドバイス

適切な圧縮レベルを選択する

  • ネットワーク転送:Z_BEST_SPEED (1) から Z_DEFAULT_COMPRESSION (-1/6) まで
  • 保存アーカイブ:Z_BEST_COMPRESSION (9)

大きなファイルにはストリーム処理を使用する

同期メソッドの使用や大きなファイルの一括処理を避け、メモリ不足を防ぎます。

zlibインスタンスを再利用する

高頻度の圧縮操作では、zlibインスタンスを再利用できます:

例

const zlib = require('zlib');
const gzip = zlib.createGzip();

// 同じ gzip インスタンスを再利用して複数のファイルを処理
function compressFile(inputFile, outputFile) {
  return new Promise((resolve, reject) => {
    fs.createReadStream(inputFile)
      .pipe(gzip)
      .pipe(fs.createWriteStream(outputFile))
      .on('finish', resolve)
      .on('error', reject);
  });
}

エラーハンドリング

圧縮・解凍プロセス中のエラーを適切に処理します:

例

const zlib = require('zlib');

// ストリーム処理のエラーハンドリング
inputStream
  .pipe(zlib.createGunzip())
  .pipe(outputStream)
  .on('error', (err) => {
    console.error('解凍プロセス中にエラー:', err);
    // リソースをクリーンアップ
  });

// 非同期コールバックのエラーハンドリング
zlib.gzip(inputData, (err, compressed) => {
  if (err) {
    console.error('圧縮失敗:', err);
    return;
  }
  // 圧縮データを処理
});

よくある質問と回答

圧縮後のデータが元のデータより大きい場合はどうすればよいですか?

この状況は通常、以下の場合に発生します:

  1. データ自体が既に圧縮されている(JPEG、MP3 など)
  2. データ量が非常に少ない(圧縮ヘッダー情報がデータ自体より大きい可能性がある)
  3. 不適切な圧縮レベルを使用している

解決策:

  • データが既に圧縮されているか確認する
  • 小さいデータには圧縮を無効にする
  • 異なる圧縮レベルを試す

データが既に圧縮されているかどうかを判断するには?

ファイルヘッダーの確認や解凍を試みることで判断できます:

例

function isGzipped(buffer) {
  return buffer.length >= 3 &&
         buffer[0] === 0x1F &&
         buffer[1] === 0x8B &&
         buffer[2] === 0x08;
}

圧縮データが破損した場合の対処方法は?

例

try {
  const decompressed = zlib.inflateSync(compressedData);
} catch (err) {
  if (err.code === 'Z_DATA_ERROR') {
    console.error('データが破損しているか、形式が正しくありません');
  } else {
    console.error('解凍エラー:', err);
  }
}

まとめ

Node.js の zlib モジュールは強力なデータ圧縮・解凍機能を提供し、適切に使用することで以下のことが可能になります:

  • ネットワーク転送データ量を大幅に削減
  • 保存容量を節約
  • アプリケーション全体のパフォーマンスを向上

重要なポイント:

  1. シーンに応じて同期・非同期・ストリーム処理を選択する
  2. 圧縮パラメータを適切に設定し、速度と圧縮率のバランスを取る
  3. エラーとエッジケースを適切に処理する
  4. 大きなファイルにはストリーム処理を使用してメモリ問題を回避する

zlib モジュールを習得することで、Node.js アプリケーションに効率的なデータ圧縮機能を追加し、リソース使用とユーザーエクスペリエンスを最適化できます。

Node.js組み込みモジュール

その他の拡張