Как я упаковал JSON на 80% и написал свой бинарный формат
Packing Binary Is Fun
Автор вдохновился спором в Twitter о том, что «настоящие» разработчики не используют JSON, и решил создать собственный бинарный формат jBin. В статье подробно разбирается, как работает бинарная упаковка: от простого преобразования ASCII до varint, схем и упаковки типа поля в один байт. В итоге ему удалось сократить JSON-полезную нагрузку на 80% и попутно изобрести целый язык описания схем.
«Насколько сложно сделать собственный бинарный формат?» — Наверное, это просто небольшая запись в режиме wb. К сожалению, это была не просто запись в режиме wb.
- trashb
Мне не хватает нескольких важных частей, которые, я бы сказал, нужны любому (бинарному) формату.
- магический заголовок
- номер версии
- crc или проверка на повреждение данных
Кроме того, я бы сказал, что в этом случае лучше написать собственный текстовый парсер, а не парсить бинарный формат; это похоже на спор о unixlike config против windows regedit. Я предпочёл бы что-то другое, а не json, но всё ещё читаемое как txt.
Даже приведённый внизу пример json можно сжать с 418 символов до 166, заменив имена полей на одиночные символы и убрав пробелы. Почти вся экономия в этом формате достигается за счёт отсутствия имён полей и позиционно-зависимой раскладки. Можно выбрать разделители или организовать так, чтобы байт указывал тип (+размер), например, следующая строка кодирует пример данных почти (85 байт против 80 байт) так же эффективно, но при этом остаётся читаемой и поддерживает интерпретацию utf-8.
123456789;LeroyJenkins;60;alliance;p,100,200,300;i,999,1,1;i,45,100,0;a,s,120;a,a,45;
Можно оптимизировать дальше, разрешив повторяющиеся записи и допустив предполагаемые значения из заданного по умолчанию, и отправляя только дельты, что может зависеть от типа ожидаемых данных.
{ "itemId": 999, "quantity": 1, "isSoulbound": false }
i,999,1,0
могло бы стать:
default = { "itemId": 0, "quantity": 1, "isSoulbound": false }
{ "itemId": 999}
i,999
- ErikHuisman
Я тоже хочу быть настоящим разработчиком, так что я просто GZIP-ую JSON, чтобы сделать его бинарным.
- Skwid
Одним из моих любимых приключений по стрижке яка на прошлой работе было написание парсера in place UBJSON-декодера для ~1 МБ данных на устройстве с примерно таким же объёмом свободной памяти. Быстрый (достаточно) доступ по ключу, бинарный поиск с несколькими сокращениями для преимущественно числовой полезной нагрузки.
Он строил индекс размером, может, 30 байт, чтобы ускорить процесс, но также чтобы продолжать работать с хвостом старого сообщения, пока новое перезаписывает его начало.
Должен ли был дизайн системы требовать всего этого от устройства с 4 МБ памяти? Вероятно, нет. Но это работало, и я отлично провёл время