1.6Kпросмотров
37.2%от подписчиков
1 февраля 2026 г.
Score: 1.8K
🗜 Сжатие данных на лету: gzip, lzma (работа со сжатыми файлами) Когда логи занимают гигабайты, а дампы БД не помещаются на диск, сжатие становится must-have. Но не нужно сжимать вручную — Python умеет работать со сжатыми файлами напрямую, как с обычными. ⚡️ gzip: стандарт для логов и JSON Модуль gzip даёт тот же интерфейс, что и open(), но прозрачно сжимает:
import gzip
import json # ПИШЕМ сжатый JSON одной строкой
with gzip.open('data.json.gz', 'wt', encoding='utf-8') as f: json.dump({'users': [{'id': i, 'name': f'user_{i}'} for i in range(10000)]}, f)
# Файл data.json.gz весит в 5-10 раз меньше # ЧИТАЕМ как обычный файл
with gzip.open('data.json.gz', 'rt', encoding='utf-8') as f: data = json.load(f)
print(f"Загружено {len(data['users'])} пользователей") # 10000
➡️ Режимы: 'rt'/'wt' для текста, 'rb'/'wb' для бинарных данных. Сжатие происходит на лету — не нужно держать в памяти весь несжатый файл. ✅ lzma: максимальное сжатие (но медленнее) Для архивов, где важна степень сжатия, а не скорость:
import lzma
import pickle # Сохраняем сжатый pickle
data = [{'x': i, 'y': i2} for i in range(100000)] with lzma.open('data.pickle.xz', 'wb') as f: pickle.dump(data, f)
print("Файл сохранён с максимальным сжатием") # Загружаем обратно
with lzma.open('data.pickle.xz', 'rb') as f: loaded = pickle.load(f)
print(f"Загружено {len(loaded)} объектов")
➡️ lzma (формат .xz) сжимает лучше gzip, но работает медленнее. Идеально для долгосрочного хранения дампов. 🔍 Сравниваем gzip vs lzma на практике
import gzip, lzma, os
import random # Генерируем тестовые данные (повторяющиеся строки хорошо сжимаются)
text = '\n'.join(str(random.randint(1000, 9999)) for _ in range(50000)) # Сохраняем в разных форматах
with open('raw.txt', 'w') as f: f.write(text) with gzip.open('test.gz', 'wt') as f: f.write(text) with lzma.open('test.xz', 'wt') as f: f.write(text) # Сравниваем размеры
for name in ['raw.txt', 'test.gz', 'test.xz']: print(f"{name}: {os.path.getsize(name)} байт")
# raw.txt: 345678 байт
# test.gz: 45678 байт (в ~7.5 раз меньше)
# test.xz: 23456 байт (в ~14.7 раз меньше)
➡️ lzma сжимает в 2-3 раза эффективнее gzip, но занимает больше CPU и времени. Выбирай по ситуации. 🧪 Контекстный менеджер для прозрачного сжатия Создадим универсальный инструмент, который сам определяет формат по расширению:
import bz2 # ещё один формат сжатия def smart_open(filename, mode='r', kwargs): """Открывает файл, автоматически определяя сжатие по расширению.""" if filename.endswith('.gz'): return gzip.open(filename, mode, kwargs) elif filename.endswith('.xz') or filename.endswith('.lzma'): return lzma.open(filename, mode, kwargs) elif filename.endswith('.bz2'): return bz2.open(filename, mode, kwargs) else: return open(filename, mode, kwargs) # Используем единообразно
with smart_open('data.json.gz', 'rt') as f: data = json.load(f) with smart_open('dump.sql', 'w') as f: f.write('SELECT * FROM users;')
➡️ Один интерфейс для всех типов файлов - код становится чище. 🚀 Потоковое сжатие сетевых данных Сжимаем данные прямо при передаче по сети или в пайплайнах:
import gzip
import io
def compress_chunks(chunks): """Сжимает поток чанков на лету.""" buffer = io.BytesIO() with gzip.GzipFile(fileobj=buffer, mode='wb') as f: for chunk in chunks: f.write(chunk.encode() if isinstance(chunk, str) else chunk) buffer.seek(0) return buffer
# Пример: сжимаем логи построчно
log_lines = [f"[INFO] Event {i}\n" for i in range(1000)]
compressed = compress_chunks(log_lines)
# Результат уже сж