Внешняя компонента 1С для потокового сжатия и распаковки gzip/deflate (Windows/Linux)

13.01.25

Разработка - Разработка внешних компонент

Внешняя компонента 1С для сжатия и распаковки данных в формате gzip/zlib/deflate. Использует библиотеку zlib. Отличие от существующих решений: 1) обработка данных в потоковом режиме, 2) поддержка всех серверных архитектур 1С, как Windows, так и Linux. Реализована по технологии Native API на C++. Доступен исходный код.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Внешняя компонента Zstream для потокового сжатия и распаковки gzip/deflate (Windows/Linux)
.zip 684,50Kb
0
0 Скачать (10 SM) Купить за 4 550 руб.
Исходный код внешней компоненты Zstream
.zip 4,59Mb
0
0 Скачать (10 SM) Купить за 4 550 руб.

Итак, пришло время вернуться к теме «Yet another unpack»))). А точнее, к теме обработки данных в формате gzip/zlib/deflate. За свою практику мне пришлось всего дважды столкнуться с необходимостью обработки данных, сжатых алгоритмом Deflate. Первый раз случился несколько лет назад, и я тогда воспользовался внешней компонентой, опубликованной здесь, на Инфостарте (//infostart.ru/1c/tools/487987/). Спасибо автору, но, к сожалению, в то время его компонента работала только на 32-разрядной платформе Windows, и пришлось вскоре от нее отказаться, т.к. 32-разрядный сервер 1С нынче мало где встретишь. (Признаюсь, я тогда докатился до того, что написал свою реализацию алгоритма распаковки на языке 1С, работало правильно, но дико медленно, всё-таки 1С – язык не для подобных задач). Второй раз случился недавно, и я решил закрыть этот гештальт окончательно.

Задача имеет следующий вид: на вход поступают данные в формате XML, сжатые в GZIP (ещё и закодированные поверх в Base64, но это пока опустим). Данные имеют табличную форму и их требуется загрузить в таблицу БД (в справочник, в регистр сведений – не суть). Объем данных в поступающем файле довольно большой, и может исчисляться мегабайтами даже в сжатом виде (на самом деле, данные мне приходят не из файла, а из ответа веб-сервиса, но, опять же, не суть).

XML имеет низкую информационную плотность, и прекрасно жмётся более, чем в 10 раз. Будучи распакованным в памяти целиком, он может превратиться в «бомбу» размером в сотню мегабайт, что нанесет ощутимый удар по ресурсам памяти сервера. Конечно, можно было бы выполнить распаковку из файла в файл, а потом уже читать распакованный XML из файла в потоковом режиме, но перекачивать десятки мегабайт через дисковую память – не очень красивое решение с точки зрения производительности, да и вообще. Хотелось бы реализовать прямую распаковку в памяти, но в потоковом режиме, т. е. блоками разумного размера, чтобы объем используемой памяти не зависел от общего объема входных данных.

Решение должно работать на любых серверных архитектурах платформы 1С. Неизвестно, какой сервер будет использовать наш заказчик, он может оказаться как на Windows, так и на Linux.

Отсюда следуют два ключевых требования к внешней компоненте:

  • Обработка данных в потоковом режиме.

  • Поддержка всех серверных архитектур 1С: как Windows, так и Linux.

В нашем распоряжении есть популярная библиотека zlib (авторы Jean-loup Gailly и Mark Adler, https://www.zlib.net/). Написана на C, поставляется в виде исходных текстов и может быть собрана под любую целевую архитектуру. Собственно, на этой библиотеке и построен архиватор gzip.

Базовые функции zlib ориентированы как раз на потоковую обработку (сжатие и распаковку) данных блоками произвольного размера: именно то, что нам нужно. Все функции этой библиотеки для работы с gzip-файлами являются уже вторичной надстройкой над базовыми потоковыми функциями.

 
 Интересный факт

 

Перехожу к главному.

Внешняя компонента Zstream является оберткой для библиотеки zlib и открывает доступ к ее базовым функциям сжатия и распаковки. Она разработана по технологии 1C Native API и поддерживает следующие архитектуры 1С:

  • Windows i386

  • Windows x86_64

  • Linux i386

  • Linux x86_64

  • Linux arm64

Решение ориентировано, в первую очередь, для работы на сервере. Можно использовать его и на клиенте, но не на веб-клиенте (согласно документации 1С, веб-клиент не умеет обмениваться с ВК объектами типа ДвоичныеДанные).

(Энтузиасты подскажут, что вместо двоичных данных можно было бы передавать строки, закодированные в Base64 – энтузиастам флаг в руки, исходники ВК я выложил).

Библиотека zlib встроена как статическая (это значит - никаких дополнительных .dll и .so).

 

Компонента разработана по принципу «ничего лишнего». Архитектурно она представляет собой потоковый процессор и у нее всего два основных метода: Записать и Прочитать.

Пример подключения и установки режимов (на сервере):

	ПодключитьВнешнююКомпоненту(Местоположение, "Zstream",
		ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.Изолированно);
	
	ПроцессорПотока = Новый("AddIn.Zstream.Zstream");
	ПроцессорПотока.РежимОбработки = ПроцессорПотока.РежимОбработки_Кодирование;
	ПроцессорПотока.ТипКодировки = ПроцессорПотока.ТипКодировки_Gzip;

 

Пример обработки потока:

	Пока Истина Цикл
		
		ВходнойБлок = ... // ДвоичныеДанные - очередная порция входных данных
		КонецВвода = ... // Булево - признак конца входного потока

		ПроцессорПотока.Записать(ВходнойБлок,, КонецВвода);

		Пока Истина Цикл
		
			ВыходнойБлок = ПроцессорПотока.Прочитать(РазмерБлока); // ДвоичныеДанные - очередная порция выходных данных
			Если ВыходнойБлок <> Неопределено Тогда
				... // используем полученные данные
			Иначе
				Прервать;
			КонецЕсли;
			
		КонецЦикла;

		Если ПроцессорПотока.КонецПотока ИЛИ ПроцессорПотока.Ошибка Тогда
			Прервать;
		КонецЕсли;

	КонецЦикла;

 

Рассмотрим подробнее.

После создания объекта Zstream нужно установить режим обработки потока (свойство РежимОбработки): кодирование (сжатие) или декодирование (распаковка). Также нужно установить тип кодировки (свойство ТипКодировки): Gzip, Zlib или Deflate.

Если мы будем распаковывать данные и нам заранее неизвестен входной формат данных (но мы точно знаем, что в деле замешана zlib), можно установить тип кодировки Авто – это приведет к попытке автоматически определить формат по заголовку gzip или zlib. Но если входные данные окажутся в формате Deflate, который вообще не содержит никакого заголовка, будет возвращена ошибка.

Если мы собираемся сжимать данные, то дополнительно можно установить уровень сжатия (свойство УровеньСжатия). Для кодировки Gzip можно установить некоторые сведения gzip-заголовка: имя и дату/время исходного файла (свойства ИмяФайла и ДатаФайла). Для распаковки данных всего этого делать не нужно. Но при распаковке можно, наоборот, прочитать имя и дату/время исходного файла, обращаясь к тем же свойствам объекта (при условии, что входной формат - gzip).

Для установки свойств объекта используются «встроенные константы» - специальные свойства объекта, доступные только для чтения и возвращающие некоторые предопределенные значения. Для установки свойств следует использовать именно свойства-константы (нельзя рассчитывать на то, что возвращаемые ими значения не изменятся в следующей версии ВК). Вот список свойств-констант:

  • РежимОбработки_Кодирование - Число

  • РежимОбработки_Декодирование - Число

  • ТипКодировки_Deflate - Число

  • ТипКодировки_Gzip - Число

  • ТипКодировки_Zlib - Число

  • ТипКодировки_Авто - Число

  • УровеньСжатия_ПоУмолчанию - Число

  • УровеньСжатия_БезСжатия - Число

  • УровеньСжатия_ЛучшаяСкорость - Число

  • УровеньСжатия_ЛучшееСжатие - Число

 

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

Входной поток данных мы получаем откуда угодно: из файла, из базы данных, из ответа веб-сервиса. Получаем данные блоками в виде объектов ДвоичныеДанные. Размер блока может быть любым: от сколь угодно малого (вплоть до блока размером 1 байт, но это будет серьезным ударом по производительности) до сколь угодно большого (ограничивается только объемом доступной памяти).

 

Для подачи данных на вход процессора используется метод Записать:

Записать(<Данные>, <Размер>, <КонецВвода>)

<Данные> - ДвоичныеДанные - блок данных в виде объекта ДвоичныеДанные.

<Размер> - Число - Размер блока данных в байтах. Имеет смысл указывать, только если нужно записать меньше данных, чем есть в объекте ДвоичныеДанные. Если не указано, то записывается весь объем данных.

<КонецВвода> - Булево - Признак последнего блока во входном потоке. При достижении конца входного потока необходимо передать в этом параметре значение Истина.

Метод Записать передает в обработку очередной блок данных входного потока. Если предыдущий блок данных не был обработан до конца, установка нового блока не приведет к потере данных: новый блок данных присоединяется к предыдущему. Однако, злоупотребление этим может привести к нежелательному росту объема используемой памяти. Поэтому лучше вычитать все данные предыдущего блока прежде, чем передавать в обработку следующий.

Разрешается вызывать метод с пустым блоком данных и значением КонецВвода = Истина для установки признака конца потока.

 

Для чтение обработанных данных с выхода процессора используется метод Прочитать:

Прочитать(<ПредельныйРазмер>)

<ПредельныйРазмер> - Число - Предельный размер получаемого блока данных в байтах. Возвращаемый блок данных не будет превышать заданный размер, но может оказаться меньше него. Если передать значение 0, то размер возвращаемого блока будет определен автоматически. Значение по умолчанию: 0.

Возвращаемое значение:

– ДвоичныеДанные – Блок данных в виде объекта ДвоичныеДанные, если имеются данные для чтения. Блок данных может оказаться меньше заданного предельного размера, для проверки фактического размера следует использовать метод ДвоичныеДанные.Размер().

- Неопределено – Если нет доступных данных для чтения.

Существует несколько причин, по которым метод может вернуть значение Неопределено. Определить причину можно, анализируя свойства объекта КонецПотока и Ошибка.

  • КонецПотока = Ложь: закончились данные для обработки. Следует записать очередной блок данных на вход процессора и продолжить чтение.

  • КонецПотока = Истина: входной поток данных обработан полностью, достигнут конец потока (был вызван метод Записать с признаком КонецВвода = Истина). Все дальнейшие попытки чтения будут безрезультатны.

  • Ошибка = Истина: при обработке данных произошла ошибка. Все дальнейшие попытки чтения будут безрезультатны. Ошибка может возникнуть при распаковке данных и обычно свидетельствует о повреждении входных данных.

 

Также существует еще один метод – Сбросить(). Он выполняет сброс объекта к начальному состоянию, чтобы можно было перейти к обработке нового потока данных, не пересоздавая объект Zstream. Метод не имеет параметров и возвращаемого значения.

Подробное описание методов и свойств ВК можно найти в прилагаемом файле readme.txt.

 

В комплекте с ВК идет демонстрационно-тестовая внешняя обработка ZstreamTest.epf. Она демонстрирует потоковое сжатие и распаковку «файл-в-файл». Помимо этого, она демонстрирует возможность подключения выхода потокового процессора к входу объекта ЧтениеXML. О том, как это делается, я как-нибудь расскажу в отдельной статье (но это не точно). Желающие могут разобраться самостоятельно.

 

Изображение выглядит как текст, снимок экрана, число, Шрифт Автоматически созданное описание

 

Сразу после запуска внешней обработки необходимо нажать кнопку «Установить и подключить ВК», после чего становятся доступны ее функции. Кстати, демо-обработка использует ВК на клиенте (ну лень было мне возиться с передачей файлов с клиента на сервер и обратно). Так что не пытайтесь запускать её на веб-клиенте.

В поле «Имя исходного файла» выберите исходный файл для сжатия. Выберите тип кодировки, уровень сжатия и размер блока. Поля «Имя сжатого файла» и «Имя распакованного файла» заполнятся автоматически, но вы можете их редактировать. Нажмите кнопку «Сжать файл» для сжатия файла. Нажмите кнопку «Распаковать файл» для распаковки файла. Кнопка «Получить данные заголовка» читает только информацию из заголовка gzip.

Тестирование для Windows 10 выполнялось на платформе 1С 8.3.24.1342 (i386 и x86_64). Тестирование для Linux выполнялось на Ubuntu 24.04.1 LTS (GNU/Linux 5.15.167.4-microsoft-standard-WSL2 x86_64), 1С 8.3.24.1761 (x86_64). Тестирование НЕ выполнялось для архитектур Linux i386 и arm64, ввиду отсутствия таковых в ближнем доступе. Лишь на кроссплатформенность GNU C++ надеюсь и уповаю.

Также выкладываю исходники ВК (нам нечего скрывать!). Компонента написана на C++. Серийных маньяков разработчиков внешних компонент могут заинтересовать следующие моменты:

  • Класс CAddInNative, куда я вынес ряд вещей, которые, как правило, реализуются одинаковым образом в любой ВК, независимо от ее назначения.

  • Автоматическая система сборки. Позволяет выполнять сборку одной командой сразу под все архитектуры. Да-да, одной командой сразу под Windows и Linux. Как? Читайте в readme.txt.

Внешняя компонента zlib gzip deflate потоковая обработка Windows Linux

См. также

Разработка внешних компонент POS терминал Рабочее место Розничная торговля Программист Пользователь Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Розничная и сетевая торговля (FMCG) Рестораны, кафе и фаст-фуд Реклама, PR и маркетинг Управленческий учет Платные (руб)

Медиадисплей покупателя может отображать текущую покупку на кассовом месте, показывать видеорекламу, баннеры, во время простоя разворачивать рекламу на весь экран. Экран можно использовать в качестве графического меню-борда в кафе и видеовывески. В качестве устройства отображения можно использовать Android-планшеты, смарт-телевизоры с Android, мониторы или проекторы под управлением Windows или Linux-компьютера. Linux-версия успешно запускается на одноплатных компьютерах Raspberri Pi и Orange Pi. Настраивается ЛЮБОЙ ДИЗАЙН экрана при помощи встроенного графического редактора! Решение можно масштабировать от одного экрана до тысяч экранов с централизованным управлением.

18000 руб.

30.05.2017    54092    9    69    

46

Разработка внешних компонент Программист Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 11 Платные (руб)

Внешняя компонента для конвертации PDF файлов в картинки без использования дополнительных программ. Работает на сервере и в тонком клиенте.

2400 руб.

25.06.2024    1151    3    4    

3

Разработка внешних компонент Телефония, SIP Программист Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

Внешняя компонента выполнена по технологии Native API для 1С 8.х, обеспечивает доступ к программным АТС Asterisk (FreePBX, Elastix) через AMI интерфейс. Через него можно управлять многими функциями Asterisk (определение номеров, перевод звонков, набор телефона и т. д.)

2400 руб.

04.05.2018    47351    124    66    

67

Разработка внешних компонент Программист Платформа 1С v8.3 Платформа 1C v8.2 Платные (руб)

Внешняя компонента, позволяющая посылать команды и получать ответы по GraphQL протоколу из 1С.Может быть использована при интеграции. В 1С работает на стороне "клиента".

4600 руб.

27.06.2023    3629    3    0    

5

Разработка внешних компонент Программист Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Позволяет автоматизировать работу с картинками. С помощью компоненты можно измерять размер изображений, поворачивать их, наносить водяные знаки, конвертировать из одного формата в другой. Будет очень полезна для интернет-магазинов и всех, кому постоянно требуется работать с различными графическими форматами. Выполнена по технологии NativeAPI. Работает с форматами: jpg (jpeg), png, bmp, gif, tif

3600 руб.

02.09.2010    77540    72    257    

191

Разработка внешних компонент Программист Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 Платные (руб)

Внешняя компонента позволяет работать c TWAIN-совместимым оборудованием (сканерами, камерами) . Полностью совместима со стандартной TWAIN-компонентой из БСП и может применяться как ее замена без изменения вызовов, при этом может работать с 64-разрядной платформой, а так же имеет расширенную функциональность, например, сохранение результата непосредственно в PDF без использования сторонних утилит. Прекрасно работает на сервере, тонком клиенте и веб-клиенте (проверена работа в браузерах Google Chrome, Mozilla Firefox и Microsoft Internet Explorer).

3000 руб.

12.05.2020    28722    138    100    

91

Разработка внешних компонент Системный администратор Программист Стажер Бесплатно (free)

Библиотека для работы с базами SQLite из 1С на основе внешней компоненты. Для Linux и Windows, бесплатно и с открытым исходным кодом!

14.01.2025    2187    bayselonarrend    14    

46

Разработка внешних компонент Программист Платформа 1С v8.3 Конфигурации 1cv8 Россия Бесплатно (free)

В статье описывается приложение-конструктор внешних компонент (native API). Конструктор упрощает процесс разработки за счет удобного добавления всех нужных функций и процедур в графическом режиме, с указанием их параметров и типов параметров. На выходе приложение генерирует готовый код на С++ и Rust и позволяет сразу приступить к реализации, без настройки API компоненты вручную.

04.12.2024    4836    kovalevdmv    26    

75
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. SerVer1C 860 13.01.25 09:35 Сейчас в теме
2. starik-2005 3098 13.01.25 12:06 Сейчас в теме
(1) А GZIP там есть без компонент?

ЗЫ: Без компонент всегда лучше, чем с ними. С другой стороны, если с компонентами в тыщу раз быстрее, то лучше с ними.
3. SerVer1C 860 13.01.25 13:03 Сейчас в теме
(2) GZIP = Голова(10) + [ИмяФайла\0] + Deflate + Хвост(8)
4. starik-2005 3098 13.01.25 13:31 Сейчас в теме
(3)
GZIP =
Тоже хорошо. Я так понимаю, что дефлэйт вполне себе распаковывается через хранилище значений?

ЗЫ: Я последний раз на С работал с распаковкой как раз через zlib, тогда это был файл с недействительными паспортами. Сам по себе интерфейс работы с архивом там прост до безобразия - создается потоковый объект и в/из него кладутся/вынимаются данные.
5. SerVer1C 860 13.01.25 13:42 Сейчас в теме
(4)
Я так понимаю, что дефлэйт вполне себе распаковывается через хранилище значений?

Да, если прицепите к deflate правильный заголовок.
6. user786882 12 16.01.25 17:13 Сейчас в теме
(5) Указанные вами решения мне известны, и они тоже вполне годятся в определенных ситуациях. Но это всё же некое "хакерство", практикуемое от недостатка нормальных инструментов.
Недостаток решения "имитация zip-файла" - отсутствие контроля ошибок. Т.к. он всегда возвращает ошибку, приходится ее всегда игнорировать. Если ваша программа получит поврежденные данные, она даже не сумеет этого понять. Второй недостаток - невозможность распаковки в памяти, только через файл.
Недостаток решения "имитация хранилища значения" - использование внутренних недокументированных особенностей платформы 1С. Это всегда ненадежно, т.к. в любой последующей версии 1С может это изменить и ваше решение сломается. Второй недостаток - невозможность распаковки фрагментами, а только одним куском в памяти. При большом объеме данных - большой расход памяти.
7. SerVer1C 860 16.01.25 17:21 Сейчас в теме
(6)
Недостаток решения "имитация zip-файла" - отсутствие контроля ошибок.
Если будет ошибка, то на выходе будет просто 0 байт.
Второй недостаток - невозможность распаковки в памяти
Вот как раз второе решение это исправляет.
Недостаток решения "имитация хранилища значения" - использование внутренних недокументированных особенностей платформы 1С
Вот как раз тут работает платформа, а точнее библиотека zlib (вы разве не её юзаете в своём решении??)
Второй недостаток - невозможность распаковки фрагментами, а только одним куском в памяти
Стесняюсь спросить, вы в 1С храните сжатые видосы?
9. user786882 12 16.01.25 17:31 Сейчас в теме
(7)
Если будет ошибка, то на выходе будет просто 0 байт

Ничего подобного. Будет столько байт, сколько прочиталось до поврежденного места.

(7)
Вот как раз тут работает платформа, а точнее библиотека zlib

Так и есть, но, повторюсь - это недокументированная возможность, и это создает риски. Завтра 1С возьмет и добавит туда какой-нибудь свой внутренний заголовок - и ваше решение перестанет работать.

(7)
Стесняюсь спросить, вы в 1С храните сжатые видосы?

Видосы нет, а вот xml размером 100Мб (в распакованном виде) может прийти запросто.
10. SerVer1C 860 16.01.25 17:43 Сейчас в теме
(9)
Так и есть, но, повторюсь - это недокументированная возможность, и это создает риски. Завтра 1С возьмет и добавит туда какой-нибудь свой внутренний заголовок - и ваше решение перестанет работать.

Если 1С так сделает, то никто больше не сможет получить данные из своих баз, которые хранятся в полях с типом ХранилищеЗначения.
вот xml размером 100Мб (в распакованном виде) может прийти запросто

В 2К25-м году то... Вроде на самой слабой "малинке" ща 2 гига оперативы )

Не поймите меня неправильно, не буду нахваливать своё решение, но с 2017-го года алгоритм работает как швейцарские часы )
ваше решение тоже имеет право на существование, и хорошо, что есть энтузиасты, которые делают подобные проекты, но, имхо, вы немного опоздали с deflate
11. user786882 12 16.01.25 19:56 Сейчас в теме
(10)
Если 1С так сделает, то никто больше не сможет получить данные из своих баз, которые хранятся в полях с типом ХранилищеЗначения.


В базе может храниться в старом формате, а в памяти - в новом.

(10)
Вроде на самой слабой "малинке" ща 2 гига оперативы

Если речь идет о сервере, то там может быть и 256 гиг. Но также на сервере работает множество процессов. И если каждый процесс будет отхватывать себе память сотнями Мб... Короче, экономия памяти - это признак хорошего тона в программировании. Сейчас этим пренебрегают, в результате получаем софт, который тормозит даже на шикарном железе.
8. user786882 12 16.01.25 17:23 Сейчас в теме
(4)
Сам по себе интерфейс работы с архивом там прост до безобразия - создается потоковый объект и в/из него кладутся/вынимаются данные

Так и есть, и я воспроизвел этот подход в ВК, без лишних наворотов.
Оставьте свое сообщение