DevToys Pro

бесплатные веб-инструменты для разработчиков

Блог
Оцените нас:
Попробуйте расширение для браузера:
← Вернуться к блогу

GZip vs Deflate vs Zlib — Форматы и заголовки

14 мин чтения

Вы пытаетесь распаковать данные и получаете ошибки "invalid header" или "incorrect header check". Или, возможно, сжатые данные работают с одним инструментом, но не работают с другим. Проблема? GZip, Deflate и Zlib используют один и тот же базовый алгоритм сжатия (DEFLATE), но оборачивают его в разные заголовки и контрольные суммы. Понимание этих различий форматов критически важно для отладки проблем со сжатием, работы с API и выбора правильного формата сжатия.

Ядро: Алгоритм DEFLATE

В основе всех трёх форматов лежит алгоритм сжатия DEFLATE, определённый в RFC 1951. DEFLATE объединяет LZ77 (сжатие со скользящим окном) с кодированием Хаффмана для достижения эффективного сжатия данных. Это тот же алгоритм, который используется в ZIP файлах, PNG изображениях и HTTP-сжатии.

DEFLATE создаёт необработанный поток сжатых данных без заголовков, контрольных сумм и метаданных об исходных данных. Этот необработанный формат эффективен, но требует дополнительной обёртки для практического использования.

Формат #1: GZip (RFC 1952)

GZip — самый распространённый формат, с которым вы столкнётесь. Он оборачивает сжатые DEFLATE данные с:

  • 10-байтовым заголовком: Начинается с магических байтов 1F 8B
  • Метаданными: Метод сжатия, флаги, временная метка, тип ОС
  • Опциональными дополнениями: Исходное имя файла, комментарий, дополнительные поля
  • Сжатые DEFLATE данные
  • 8-байтовым футером: Контрольная сумма CRC-32 + несжатый размер (mod 2^32)

Структура заголовка GZip

Байт 0-1:   1F 8B          # Магическое число (идентифицирует формат GZip)
Байт 2:     08             # Метод сжатия (08 = DEFLATE)
Байт 3:     Флаги          # Опциональные функции (имя файла, комментарий и т.д.)
Байт 4-7:   Временная метка # Время модификации (Unix timestamp)
Байт 8:     Доп. флаги     # Индикатор уровня сжатия
Байт 9:     ОС             # Операционная система (0=FAT, 3=Unix, 11=NTFS)
...         [опционально]  # Имя файла, комментарий, дополнительные данные
...         DEFLATE данные # Сжатая полезная нагрузка
...         CRC-32         # 4 байта: контрольная сумма несжатых данных
...         Размер         # 4 байта: несжатый размер mod 2^32

Когда используется GZip

  • HTTP-сжатие: Content-Encoding: gzip
  • Сжатие файлов: Файлы .gz (например, archive.tar.gz)
  • Утилита командной строки Gzip: gzip / gunzip
  • Git объекты: Сжимаются в формате GZip

Пример GZip

# Исходный текст
"Hello, World!"

# Сжатый GZip (hex):
1F 8B 08 00 00 00 00 00 00 03 F3 48 CD C9 C9 D7 
51 08 CF 2F CA 49 51 04 00 D0 C3 4A EC 0D 00 00 00

# Разбор:
1F 8B       - Магическое число GZip
08          - Сжатие DEFLATE
00          - Нет флагов
00 00 00 00 - Нет временной метки
00          - Сжатие по умолчанию
03          - ОС Unix
...         - Сжатые DEFLATE данные
D0 C3 4A EC - Контрольная сумма CRC-32
0D 00 00 00 - Несжатый размер (13 байт)

Формат #2: Zlib (RFC 1950)

Zlib похож на GZip, но с более простой структурой заголовка. Он оборачивает сжатые DEFLATE данные с:

  • 2-байтовым заголовком: Метод сжатия и флаги
  • Сжатыми DEFLATE данными
  • 4-байтовым футером: Контрольная сумма Adler-32 (быстрее чем CRC-32)

Структура заголовка Zlib

Байт 0:     CMF            # Метод сжатия и флаги
            Биты 0-3:  CM = 8       # Метод сжатия (8 = DEFLATE)
            Биты 4-7:  CINFO       # Размер окна (log2(window) - 8)
Байт 1:     FLG            # Флаги
            Биты 0-4:  FCHECK      # Контрольная сумма заголовка
            Бит 5:     FDICT       # Флаг предустановленного словаря
            Биты 6-7:  FLEVEL      # Уровень сжатия
...         DEFLATE данные # Сжатая полезная нагрузка
...         Adler-32       # 4 байта: контрольная сумма несжатых данных

Когда используется Zlib

  • PNG изображения: Каждый PNG-чанк сжат Zlib
  • PDF файлы: Встроенные потоки используют Zlib-сжатие
  • Модуль Python zlib: Формат по умолчанию
  • Java Deflater/Inflater: Формат по умолчанию
  • OpenSSL: Формат сжатия по умолчанию

Пример Zlib

# Исходный текст
"Hello, World!"

# Сжатый Zlib (hex):
78 9C F3 48 CD C9 C9 D7 51 08 CF 2F CA 49 51 04 
00 1F 9E 04 6A

# Разбор:
78          - CMF: DEFLATE, окно 32K
9C          - FLG: Сжатие по умолчанию, контрольная сумма
...         - Сжатые DEFLATE данные
1F 9E 04 6A - Контрольная сумма Adler-32

Формат #3: Необработанный DEFLATE

Необработанный DEFLATE — это просто поток сжатых данных без заголовков или контрольных сумм вообще. Это самый компактный формат, но требует внешнего знания о данных для правильной распаковки и проверки.

Когда используется необработанный DEFLATE

  • HTTP-сжатие: Content-Encoding: deflate (технически должен быть Zlib, но некоторые серверы отправляют необработанный DEFLATE)
  • ZIP файлы: Отдельные записи используют необработанный DEFLATE (заголовки/контрольные суммы находятся в структуре ZIP)
  • 7-Zip: Метод DEFLATE использует необработанный формат

Пример необработанного DEFLATE

# Исходный текст
"Hello, World!"

# Сжатый необработанный DEFLATE (hex):
F3 48 CD C9 C9 D7 51 08 CF 2F CA 49 51 04 00

# Нет заголовка, нет футера, только сжатые данные

Таблица сравнения форматов

| Функция          | GZip      | Zlib      | Raw DEFLATE |
|------------------|-----------|-----------|-------------|
| Размер заголовка | 10+ байт  | 2 байта   | 0 байт      |
| Контр. сумма     | CRC-32    | Adler-32  | Нет         |
| Метаданные       | Да        | Минимум   | Нет         |
| Накладные расх.  | ~18 байт  | ~6 байт   | 0 байт      |
| Магич. байты     | 1F 8B     | 78 XX     | Нет         |
| Инфо о размере   | Да        | Нет       | Нет         |
| Врем. метка      | Да        | Нет       | Нет         |
| RFC              | 1952      | 1950      | 1951        |

Почему инструменты дают сбой: Несоответствие формата

Самая распространённая ошибка сжатия — попытка распаковать данные с неправильным ожиданием формата:

Ошибка #1: "incorrect header check"

Вы пытаетесь распаковать данные GZip как Zlib (или наоборот). Декомпрессор читает первые два байта как заголовок Zlib, и контрольная сумма не проходит проверку.

# Пример Python: Неправильный формат
import zlib

gzip_data = b'\x1f\x8b\x08...'  # Формат GZip
zlib.decompress(gzip_data)
# Ошибка: zlib.error: Error -3 while decompressing: incorrect header check

Решение: Используйте zlib.decompress(data, wbits=16+zlib.MAX_WBITS) для GZip или gzip.decompress()

Ошибка #2: "invalid stored block lengths"

Вы пытаетесь распаковать данные Zlib как необработанный DEFLATE (или наоборот).

# Пример Python: Отсутствующий заголовок
import zlib

zlib_data = b'\x78\x9c...'  # Формат Zlib
zlib.decompress(zlib_data, wbits=-zlib.MAX_WBITS)  # Режим raw DEFLATE
# Ошибка: zlib.error: Error -5 while decompressing: incomplete or truncated stream

Решение: Используйте положительный wbits для Zlib, отрицательный для необработанного DEFLATE

Ошибка #3: "invalid distance too far back"

Вы распаковываете с неправильным размером окна или данные повреждены.

API сжатия в разных языках программирования

Python

import zlib
import gzip

# Формат GZip
gzip_data = gzip.compress(b"Hello")       # Создать GZip
original = gzip.decompress(gzip_data)     # Распаковать GZip

# Формат Zlib (по умолчанию)
zlib_data = zlib.compress(b"Hello")       # Создать Zlib
original = zlib.decompress(zlib_data)     # Распаковать Zlib

# Необработанный DEFLATE
deflate_data = zlib.compress(b"Hello", wbits=-zlib.MAX_WBITS)
original = zlib.decompress(deflate_data, wbits=-zlib.MAX_WBITS)

# Автоопределение формата
def decompress_any(data):
    # Попробовать GZip
    if data[:2] == b'\x1f\x8b':
        return gzip.decompress(data)
    # Попробовать Zlib
    elif data[:1] == b'\x78':
        return zlib.decompress(data)
    # Попробовать raw DEFLATE
    else:
        return zlib.decompress(data, wbits=-zlib.MAX_WBITS)

JavaScript (Node.js)

const zlib = require('zlib');

// Формат GZip
const gzipData = zlib.gzipSync(Buffer.from('Hello'));
const original = zlib.gunzipSync(gzipData);

// Формат Zlib
const zlibData = zlib.deflateSync(Buffer.from('Hello'));
const original = zlib.inflateSync(zlibData);

// Необработанный DEFLATE
const deflateData = zlib.deflateRawSync(Buffer.from('Hello'));
const original = zlib.inflateRawSync(deflateData);

Java

import java.util.zip.*;

// Формат Zlib (по умолчанию)
Deflater deflater = new Deflater();
deflater.setInput(data);
deflater.finish();
byte[] zlibData = new byte[1024];
int size = deflater.deflate(zlibData);

// Необработанный DEFLATE
Deflater deflater = new Deflater(Deflater.DEFAULT_COMPRESSION, true); // nowrap=true
// ... то же, что и выше

// Формат GZip
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = new GZIPOutputStream(baos);
gzos.write(data);
gzos.close();
byte[] gzipData = baos.toByteArray();

Путаница с HTTP Content-Encoding

HTTP-заголовок Content-Encoding: deflate неоднозначен. Согласно RFC 2616, он должен использовать формат Zlib, но многие реализации используют вместо этого необработанный DEFLATE.

Что ожидают браузеры

  • Content-Encoding: gzip — Формат GZip (наиболее распространён, лучше всего поддерживается)
  • Content-Encoding: deflate — Формат Zlib (спецификация RFC) ИЛИ необработанный DEFLATE (распространённая ошибка)
  • Content-Encoding: br — Brotli (новее, лучше сжатие)

Лучшая практика для HTTP

Всегда используйте GZip для HTTP-сжатия. Он универсально поддерживается, чётко определён и избегает неоднозначности deflate.

# Конфигурация Nginx
gzip on;
gzip_types text/plain text/css application/json application/javascript;

# Конфигурация Apache
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/plain text/xml
</IfModule>

Определение формата сжатия

Вы можете определить формат, проверив первые несколько байтов:

function detectFormat(data) {
  if (data.length < 2) return 'unknown';
  
  // Проверить магическое число GZip
  if (data[0] === 0x1f && data[1] === 0x8b) {
    return 'gzip';
  }
  
  // Проверить заголовок Zlib
  // Байт CMF: 0x78 обычен (DEFLATE с окном 32K)
  // Байт FLG варьируется, но контрольная сумма заголовка должна быть корректной
  if (data[0] === 0x78 && (data[0] * 256 + data[1]) % 31 === 0) {
    return 'zlib';
  }
  
  // Может быть raw DEFLATE (надёжное определение невозможно)
  return 'raw-deflate (или неизвестно)';
}

// Примеры
detectFormat([0x1f, 0x8b, 0x08, ...]);  // 'gzip'
detectFormat([0x78, 0x9c, ...]);        // 'zlib'
detectFormat([0x78, 0xda, ...]);        // 'zlib' (более высокое сжатие)
detectFormat([0xf3, 0x48, ...]);        // 'raw-deflate (или неизвестно)'

Уровни сжатия и компромиссы

Все три формата поддерживают уровни сжатия (обычно 0-9 или 1-9, где выше = лучше сжатие, но медленнее):

  • Уровень 0: Без сжатия (только хранение) — быстро, но без экономии места
  • Уровень 1-3: Быстрое сжатие — хорошо для данных в реальном времени
  • Уровень 6: По умолчанию — сбалансированная скорость и сжатие
  • Уровень 9: Максимальное сжатие — медленно, но лучшее соотношение

Сравнение степени сжатия

Для типичных текстовых данных (таких как JSON или HTML):

  • GZip уровень 6: ~70-80% сжатие (в 3-5 раз меньше)
  • GZip уровень 9: ~75-85% сжатие (немного лучше, гораздо медленнее)
  • Brotli уровень 11: ~80-90% сжатие (лучше для статических файлов)

Реальный сценарий отладки

Вы загружаете сжатые API-ответы и получаете ошибки декомпрессии. Вот как отладить:

Шаг 1: Захватить необработанные данные

# Пример Python
import requests

response = requests.get('https://api.example.com/data', 
                       headers={'Accept-Encoding': 'gzip'})

# Необработанные сжатые данные
compressed = response.content

# Проверить заголовок Content-Encoding
print(response.headers.get('Content-Encoding'))  # 'gzip' или 'deflate'

# Проверить первые байты
print(compressed[:10].hex())  # '1f8b08...' = GZip

Шаг 2: Определить формат

# Проверить магические байты
if compressed[:2] == b'\x1f\x8b':
    print("Формат: GZip")
    data = gzip.decompress(compressed)
elif compressed[:1] == b'\x78':
    print("Формат: Zlib")
    data = zlib.decompress(compressed)
else:
    print("Формат: Raw DEFLATE (или неизвестно)")
    try:
        data = zlib.decompress(compressed, wbits=-zlib.MAX_WBITS)
    except:
        print("Тоже не raw DEFLATE!")

Шаг 3: Проверить декомпрессию

# Проверить, выглядят ли распакованные данные корректно
print(f"Распакованный размер: {len(data)} байт")
print(f"Первые 100 символов: {data[:100]}")

# Попробовать распарсить как JSON, если ожидается
import json
try:
    parsed = json.loads(data)
    print("Корректный JSON!")
except:
    print("Не корректный JSON - возможно всё ещё сжато или повреждено")

Использование инструментов сжатия

При работе со сжатыми данными используйте инструменты, поддерживающие все три формата:

Инструмент GZip в DevToys Pro поддерживает:

  • Форматы GZip, Zlib и необработанный DEFLATE
  • Автоматическое определение формата
  • Настраиваемые уровни сжатия
  • Кодирование Base64 для передачи
  • Сообщения об ошибках при неудаче декомпрессии

Лучшие практики

  1. Используйте GZip для HTTP и сжатия файлов — наиболее широко поддерживается
  2. Используйте Zlib для встроенного сжатия — PNG, PDF, внутренние структуры данных
  3. Избегайте необработанного DEFLATE — отсутствие контрольной суммы делает обнаружение повреждения невозможным
  4. Всегда проверяйте контрольные суммы — обнаруживайте повреждённые данные на ранней стадии
  5. Документируйте выбор формата — предотвратите проблемы интеграции
  6. Тестируйте с несжимаемыми данными — убедитесь, что ваш код корректно обрабатывает расширение
  7. Рассмотрите Brotli для статических файлов — лучше сжатие, чем GZip

Типичные ошибки

  • Предположение, что "deflate" означает raw DEFLATE — должен быть Zlib, но не всегда
  • Не проверять магические байты — приводит к загадочным ошибкам декомпрессии
  • Игнорирование ошибок контрольной суммы — повреждённые данные могут вызвать проблемы безопасности
  • Использование неправильного размера окна — вызывает ошибки "invalid distance"
  • Сжатие уже сжатых данных — тратит CPU и фактически увеличивает размер

Ключевые выводы

  • GZip, Zlib и необработанный DEFLATE используют один алгоритм DEFLATE
  • GZip: 10-байтовый заголовок + CRC-32, наиболее распространён для файлов и HTTP
  • Zlib: 2-байтовый заголовок + Adler-32, используется в PNG, PDF и многих библиотеках
  • Необработанный DEFLATE: без заголовков или контрольных сумм, используется в ZIP файлах
  • Определяйте формат по магическим байтам: 0x1f8b = GZip, 0x78XX = Zlib
  • HTTP-кодирование "deflate" неоднозначно — придерживайтесь GZip
  • Всегда используйте контрольные суммы для обнаружения повреждённых данных

Связанные инструменты: