Heatshrink
Модуль сжатия данных для встраиваемых систем. Использует алгоритм LZSS и поддерживает как одноразовую, так и потоковую обработку.
Heatshrink особенно полезен для:
- Сжатия данных перед передачей по сети (MQTT, HTTP)
- Компактного хранения логов и конфигураций
- OTA обновлений
- Сжатия Lua скриптов
heatshrink.encode(data [, window, lookahead])
Сжимает данные.
Аргументы:
- data: строка с данными для сжатия
- window (опционально): размер окна поиска (4-14, по умолчанию 10 = 1024 байта)
- lookahead (опционально): размер предпросмотра (3 до window-1, по умолчанию 5 = 32 байта)
Если для окна 4 или 5 параметр lookahead не указан, модуль автоматически использует window - 1.
Возвращает: сжатые данные (строка).
-- Простое сжатие с параметрами по умолчанию
local original = "Hello, World! Hello, World! Hello, World!"
local compressed = heatshrink.encode(original)
print("Original: " .. #original .. " bytes")
print("Compressed: " .. #compressed .. " bytes")
Original: 41 bytes
Compressed: 22 bytes
-- Сжатие с пользовательскими параметрами
local compressed = heatshrink.encode(data, 8, 4)
-- Или через таблицу
local compressed = heatshrink.encode(data, {window = 8, lookahead = 4})
heatshrink.decode(data [, window, lookahead, max_output])
Распаковывает данные. Параметры window и lookahead должны совпадать с теми, что использовались при сжатии.
Аргументы:
- data: строка со сжатыми данными
- window (опционально): размер окна 4-15 (должен совпадать с encode)
- lookahead (опционально): размер предпросмотра (должен совпадать с encode)
- max_output (опционально): максимальный размер результата, по умолчанию 262144 байта; допустимый диапазон 1-1048576 байт
Возвращает: распакованные данные (строка).
local compressed = heatshrink.encode("Hello, World!")
local decompressed = heatshrink.decode(compressed)
print(decompressed)
Hello, World!
Параметры можно передать таблицей:
local decompressed = heatshrink.decode(compressed, {
window = 10,
lookahead = 5,
max_output = 512 * 1024,
})
Для данных больше 1 МиБ используйте потоковый декодер.
heatshrink.encoder([params])
Создает объект-кодировщик для инкрементального сжатия данных. Полезен при работе с большими объемами данных или потоковой обработке.
Аргументы:
- params (опционально): таблица с параметрами {window = N, lookahead = N} или числа window, lookahead; максимальное окно кодировщика — 14
Возвращает: объект encoder.
local enc = heatshrink.encoder()
-- или
local enc = heatshrink.encoder({window = 10, lookahead = 5})
-- или
local enc = heatshrink.encoder(10, 5)
encoder:sink(data)
Подает данные на вход кодировщика.
Возвращает: количество принятых байт.
local consumed = enc:sink("Hello, World!")
encoder:poll([maxlen])
Извлекает сжатые данные из кодировщика.
Аргументы:
- maxlen (опционально): максимальный размер буфера от 1 до 65536 байт (по умолчанию 4096)
Возвращает: data, has_more (сжатые данные и флаг наличия дополнительных данных).
local data, has_more = enc:poll()
while has_more do
local more_data
more_data, has_more = enc:poll()
data = data .. more_data
end
encoder:finish()
Завершает сжатие и сбрасывает оставшиеся данные.
Возвращает: is_done (true если сжатие завершено).
local is_done = enc:finish()
while not is_done do
local data = enc:poll()
-- обработка data
is_done = enc:finish()
end
encoder:reset()
Сбрасывает состояние кодировщика для повторного использования.
enc:reset()
heatshrink.decoder([params])
Создает объект-декодер для инкрементальной распаковки данных.
Аргументы:
- params (опционально): таблица {window = N, lookahead = N, input_buffer = N}; input_buffer должен быть в диапазоне 1-65535
Возвращает: объект decoder.
local dec = heatshrink.decoder()
-- или с пользовательским буфером
local dec = heatshrink.decoder({window = 10, lookahead = 5, input_buffer = 512})
decoder:sink(data)
Подает сжатые данные на вход декодера.
Возвращает: количество принятых байт.
decoder:poll([maxlen])
Извлекает распакованные данные из декодера.
Параметр maxlen должен быть в диапазоне 1-65536 байт; значение по умолчанию — 4096.
Возвращает: data, has_more.
decoder:finish()
Завершает распаковку.
Возвращает: is_done.
decoder:reset()
Сбрасывает состояние декодера.
Константы
- heatshrink.MIN_WINDOW — минимальный размер окна (4)
- heatshrink.MAX_WINDOW — максимальный размер окна кодировщика (14)
- heatshrink.MAX_DECODER_WINDOW — максимальный размер окна декодера (15)
- heatshrink.MIN_LOOKAHEAD — минимальный размер предпросмотра (3)
- heatshrink.DEFAULT_MAX_OUTPUT — стандартный лимит результата decode (262144 байта)
- heatshrink.MAX_OUTPUT — максимальный разрешенный лимит результата decode (1048576 байт)
Примеры
Сжатие файла
-- Сжатие Lua скрипта
local f = io.open("/sd/script.lua", "r")
local content = f:read("*a")
f:close()
local compressed = heatshrink.encode(content)
local f = io.open("/sd/script.lua.hs", "w")
f:write(compressed)
f:close()
print("Compression ratio: " .. math.floor(#compressed / #content * 100) .. "%")
Потоковое сжатие для MQTT
-- Сжатие данных перед отправкой
local function compress_and_send(topic, data)
local compressed = heatshrink.encode(data)
mqtt:publish(topic .. "/compressed", compressed)
end
-- Получение и распаковка
mqtt:subscribe("sensor/data/compressed", function(topic, payload)
local data = heatshrink.decode(payload)
print("Received: " .. data)
end)
Инкрементальное сжатие большого файла
local enc = heatshrink.encoder()
local f_in = io.open("/sd/large_file.txt", "r")
local f_out = io.open("/sd/large_file.hs", "w")
-- Читаем и сжимаем по частям
while true do
local chunk = f_in:read(1024)
if not chunk then break end
enc:sink(chunk)
local data, has_more = enc:poll()
f_out:write(data)
while has_more do
data, has_more = enc:poll()
f_out:write(data)
end
end
-- Завершаем сжатие
local is_done = enc:finish()
while not is_done do
local data = enc:poll()
f_out:write(data)
is_done = enc:finish()
end
f_in:close()
f_out:close()
Рекомендации по параметрам
| Параметр | Память | Сжатие | Рекомендация |
|---|---|---|---|
| window=8, lookahead=4 | ~256 байт | среднее | для очень ограниченной памяти |
| window=10, lookahead=5 | ~1 КБ | хорошее | по умолчанию, рекомендуется |
| window=12, lookahead=6 | ~4 КБ | отличное | для максимального сжатия |
Большее окно даёт лучшее сжатие, но требует больше памяти. Lookahead обычно устанавливается как window/2.